mirror of
https://github.com/N64Recomp/N64Recomp.git
synced 2026-04-28 21:12:24 +00:00
Changed recomp port naming to N64Recomp
This commit is contained in:
parent
9b0a349a5e
commit
ff5797a2aa
11 changed files with 177 additions and 178 deletions
|
|
@ -1,10 +1,10 @@
|
|||
#ifndef __GENERATOR_H__
|
||||
#define __GENERATOR_H__
|
||||
|
||||
#include "recomp_port.h"
|
||||
#include "n64recomp.h"
|
||||
#include "operations.h"
|
||||
|
||||
namespace RecompPort {
|
||||
namespace N64Recomp {
|
||||
struct InstructionContext {
|
||||
int rd;
|
||||
int rs;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ constexpr uint32_t byteswap(uint32_t val) {
|
|||
}
|
||||
#endif
|
||||
|
||||
namespace RecompPort {
|
||||
namespace N64Recomp {
|
||||
struct Function {
|
||||
uint32_t vram;
|
||||
uint32_t rom;
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include "rabbitizer.hpp"
|
||||
|
||||
namespace RecompPort {
|
||||
namespace N64Recomp {
|
||||
using InstrId = rabbitizer::InstrId::UniqueId;
|
||||
using Cop0Reg = rabbitizer::Registers::Cpu::Cop0;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#include "rabbitizer.hpp"
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include "recomp_port.h"
|
||||
#include "n64recomp.h"
|
||||
#include "analysis.h"
|
||||
|
||||
extern "C" const char* RabbitizerRegister_getNameGpr(uint8_t regValue);
|
||||
|
|
@ -50,7 +50,7 @@ struct RegState {
|
|||
using InstrId = rabbitizer::InstrId::UniqueId;
|
||||
using RegId = rabbitizer::Registers::Cpu::GprO32;
|
||||
|
||||
bool analyze_instruction(const rabbitizer::InstructionCpu& instr, const RecompPort::Function& func, RecompPort::FunctionStats& stats,
|
||||
bool analyze_instruction(const rabbitizer::InstructionCpu& instr, const N64Recomp::Function& func, N64Recomp::FunctionStats& stats,
|
||||
RegState reg_states[32], std::vector<RegState>& stack_states) {
|
||||
// Temporary register state for tracking the register being operated on
|
||||
RegState temp{};
|
||||
|
|
@ -220,8 +220,8 @@ bool analyze_instruction(const rabbitizer::InstructionCpu& instr, const RecompPo
|
|||
return true;
|
||||
}
|
||||
|
||||
bool RecompPort::analyze_function(const RecompPort::Context& context, const RecompPort::Function& func,
|
||||
const std::vector<rabbitizer::InstructionCpu>& instructions, RecompPort::FunctionStats& stats) {
|
||||
bool N64Recomp::analyze_function(const N64Recomp::Context& context, const N64Recomp::Function& func,
|
||||
const std::vector<rabbitizer::InstructionCpu>& instructions, N64Recomp::FunctionStats& stats) {
|
||||
// Create a state to track each register (r0 won't be used)
|
||||
RegState reg_states[32] {};
|
||||
std::vector<RegState> stack_states{};
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "recomp_port.h"
|
||||
#include "n64recomp.h"
|
||||
|
||||
namespace RecompPort {
|
||||
namespace N64Recomp {
|
||||
struct JumpTable {
|
||||
uint32_t vram;
|
||||
uint32_t addend_reg;
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ struct BinaryOpFields { std::string func_string; std::string infix_string; };
|
|||
|
||||
std::vector<BinaryOpFields> c_op_fields = []() {
|
||||
std::vector<BinaryOpFields> ret{};
|
||||
ret.resize(static_cast<size_t>(RecompPort::BinaryOpType::COUNT));
|
||||
ret.resize(static_cast<size_t>(N64Recomp::BinaryOpType::COUNT));
|
||||
std::vector<char> ops_setup{};
|
||||
ops_setup.resize(static_cast<size_t>(RecompPort::BinaryOpType::COUNT));
|
||||
ops_setup.resize(static_cast<size_t>(N64Recomp::BinaryOpType::COUNT));
|
||||
|
||||
auto setup_op = [&ret, &ops_setup](RecompPort::BinaryOpType op_type, const std::string& func_string, const std::string& infix_string) {
|
||||
auto setup_op = [&ret, &ops_setup](N64Recomp::BinaryOpType op_type, const std::string& func_string, const std::string& infix_string) {
|
||||
size_t index = static_cast<size_t>(op_type);
|
||||
// Prevent setting up an operation twice.
|
||||
assert(ops_setup[index] == false && "Operation already setup!");
|
||||
|
|
@ -22,47 +22,47 @@ std::vector<BinaryOpFields> c_op_fields = []() {
|
|||
ret[index] = { func_string, infix_string };
|
||||
};
|
||||
|
||||
setup_op(RecompPort::BinaryOpType::Add32, "ADD32", "");
|
||||
setup_op(RecompPort::BinaryOpType::Sub32, "SUB32", "");
|
||||
setup_op(RecompPort::BinaryOpType::Add64, "", "+");
|
||||
setup_op(RecompPort::BinaryOpType::Sub64, "", "-");
|
||||
setup_op(RecompPort::BinaryOpType::And64, "", "&");
|
||||
setup_op(RecompPort::BinaryOpType::AddFloat, "", "+");
|
||||
setup_op(RecompPort::BinaryOpType::AddDouble, "", "+");
|
||||
setup_op(RecompPort::BinaryOpType::SubFloat, "", "-");
|
||||
setup_op(RecompPort::BinaryOpType::SubDouble, "", "-");
|
||||
setup_op(RecompPort::BinaryOpType::MulFloat, "MUL_S", "");
|
||||
setup_op(RecompPort::BinaryOpType::MulDouble, "MUL_D", "");
|
||||
setup_op(RecompPort::BinaryOpType::DivFloat, "DIV_S", "");
|
||||
setup_op(RecompPort::BinaryOpType::DivDouble, "DIV_D", "");
|
||||
setup_op(RecompPort::BinaryOpType::Or64, "", "|");
|
||||
setup_op(RecompPort::BinaryOpType::Nor64, "~", "|");
|
||||
setup_op(RecompPort::BinaryOpType::Xor64, "", "^");
|
||||
setup_op(RecompPort::BinaryOpType::Sll32, "S32", "<<");
|
||||
setup_op(RecompPort::BinaryOpType::Sll64, "", "<<");
|
||||
setup_op(RecompPort::BinaryOpType::Srl32, "S32", ">>");
|
||||
setup_op(RecompPort::BinaryOpType::Srl64, "", ">>");
|
||||
setup_op(RecompPort::BinaryOpType::Sra32, "S32", ">>"); // Arithmetic aspect will be taken care of by unary op for first operand.
|
||||
setup_op(RecompPort::BinaryOpType::Sra64, "", ">>"); // Arithmetic aspect will be taken care of by unary op for first operand.
|
||||
setup_op(RecompPort::BinaryOpType::Equal, "", "==");
|
||||
setup_op(RecompPort::BinaryOpType::NotEqual, "", "!=");
|
||||
setup_op(RecompPort::BinaryOpType::Less, "", "<");
|
||||
setup_op(RecompPort::BinaryOpType::LessEq, "", "<=");
|
||||
setup_op(RecompPort::BinaryOpType::Greater, "", ">");
|
||||
setup_op(RecompPort::BinaryOpType::GreaterEq, "", ">=");
|
||||
setup_op(RecompPort::BinaryOpType::LD, "LD", "");
|
||||
setup_op(RecompPort::BinaryOpType::LW, "MEM_W", "");
|
||||
setup_op(RecompPort::BinaryOpType::LWU, "MEM_WU", "");
|
||||
setup_op(RecompPort::BinaryOpType::LH, "MEM_H", "");
|
||||
setup_op(RecompPort::BinaryOpType::LHU, "MEM_HU", "");
|
||||
setup_op(RecompPort::BinaryOpType::LB, "MEM_B", "");
|
||||
setup_op(RecompPort::BinaryOpType::LBU, "MEM_BU", "");
|
||||
setup_op(RecompPort::BinaryOpType::LDL, "do_ldl", "");
|
||||
setup_op(RecompPort::BinaryOpType::LDR, "do_ldr", "");
|
||||
setup_op(RecompPort::BinaryOpType::LWL, "do_lwl", "");
|
||||
setup_op(RecompPort::BinaryOpType::LWR, "do_lwr", "");
|
||||
setup_op(RecompPort::BinaryOpType::True, "", "");
|
||||
setup_op(RecompPort::BinaryOpType::False, "", "");
|
||||
setup_op(N64Recomp::BinaryOpType::Add32, "ADD32", "");
|
||||
setup_op(N64Recomp::BinaryOpType::Sub32, "SUB32", "");
|
||||
setup_op(N64Recomp::BinaryOpType::Add64, "", "+");
|
||||
setup_op(N64Recomp::BinaryOpType::Sub64, "", "-");
|
||||
setup_op(N64Recomp::BinaryOpType::And64, "", "&");
|
||||
setup_op(N64Recomp::BinaryOpType::AddFloat, "", "+");
|
||||
setup_op(N64Recomp::BinaryOpType::AddDouble, "", "+");
|
||||
setup_op(N64Recomp::BinaryOpType::SubFloat, "", "-");
|
||||
setup_op(N64Recomp::BinaryOpType::SubDouble, "", "-");
|
||||
setup_op(N64Recomp::BinaryOpType::MulFloat, "MUL_S", "");
|
||||
setup_op(N64Recomp::BinaryOpType::MulDouble, "MUL_D", "");
|
||||
setup_op(N64Recomp::BinaryOpType::DivFloat, "DIV_S", "");
|
||||
setup_op(N64Recomp::BinaryOpType::DivDouble, "DIV_D", "");
|
||||
setup_op(N64Recomp::BinaryOpType::Or64, "", "|");
|
||||
setup_op(N64Recomp::BinaryOpType::Nor64, "~", "|");
|
||||
setup_op(N64Recomp::BinaryOpType::Xor64, "", "^");
|
||||
setup_op(N64Recomp::BinaryOpType::Sll32, "S32", "<<");
|
||||
setup_op(N64Recomp::BinaryOpType::Sll64, "", "<<");
|
||||
setup_op(N64Recomp::BinaryOpType::Srl32, "S32", ">>");
|
||||
setup_op(N64Recomp::BinaryOpType::Srl64, "", ">>");
|
||||
setup_op(N64Recomp::BinaryOpType::Sra32, "S32", ">>"); // Arithmetic aspect will be taken care of by unary op for first operand.
|
||||
setup_op(N64Recomp::BinaryOpType::Sra64, "", ">>"); // Arithmetic aspect will be taken care of by unary op for first operand.
|
||||
setup_op(N64Recomp::BinaryOpType::Equal, "", "==");
|
||||
setup_op(N64Recomp::BinaryOpType::NotEqual, "", "!=");
|
||||
setup_op(N64Recomp::BinaryOpType::Less, "", "<");
|
||||
setup_op(N64Recomp::BinaryOpType::LessEq, "", "<=");
|
||||
setup_op(N64Recomp::BinaryOpType::Greater, "", ">");
|
||||
setup_op(N64Recomp::BinaryOpType::GreaterEq, "", ">=");
|
||||
setup_op(N64Recomp::BinaryOpType::LD, "LD", "");
|
||||
setup_op(N64Recomp::BinaryOpType::LW, "MEM_W", "");
|
||||
setup_op(N64Recomp::BinaryOpType::LWU, "MEM_WU", "");
|
||||
setup_op(N64Recomp::BinaryOpType::LH, "MEM_H", "");
|
||||
setup_op(N64Recomp::BinaryOpType::LHU, "MEM_HU", "");
|
||||
setup_op(N64Recomp::BinaryOpType::LB, "MEM_B", "");
|
||||
setup_op(N64Recomp::BinaryOpType::LBU, "MEM_BU", "");
|
||||
setup_op(N64Recomp::BinaryOpType::LDL, "do_ldl", "");
|
||||
setup_op(N64Recomp::BinaryOpType::LDR, "do_ldr", "");
|
||||
setup_op(N64Recomp::BinaryOpType::LWL, "do_lwl", "");
|
||||
setup_op(N64Recomp::BinaryOpType::LWR, "do_lwr", "");
|
||||
setup_op(N64Recomp::BinaryOpType::True, "", "");
|
||||
setup_op(N64Recomp::BinaryOpType::False, "", "");
|
||||
|
||||
// Ensure every operation has been setup.
|
||||
for (char is_set : ops_setup) {
|
||||
|
|
@ -100,22 +100,22 @@ std::string fpr_u64_to_string(int fpr_index) {
|
|||
return fmt::format("ctx->f{}.u64", fpr_index);
|
||||
}
|
||||
|
||||
std::string unsigned_reloc(const RecompPort::InstructionContext& context) {
|
||||
std::string unsigned_reloc(const N64Recomp::InstructionContext& context) {
|
||||
switch (context.reloc_type) {
|
||||
case RecompPort::RelocType::R_MIPS_HI16:
|
||||
case N64Recomp::RelocType::R_MIPS_HI16:
|
||||
return fmt::format("RELOC_HI16({}, {:#X})", context.reloc_section_index, context.reloc_target_section_offset);
|
||||
case RecompPort::RelocType::R_MIPS_LO16:
|
||||
case N64Recomp::RelocType::R_MIPS_LO16:
|
||||
return fmt::format("RELOC_LO16({}, {:#X})", context.reloc_section_index, context.reloc_target_section_offset);
|
||||
default:
|
||||
throw std::runtime_error(fmt::format("Unexpected reloc type {}\n", static_cast<int>(context.reloc_type)));
|
||||
}
|
||||
}
|
||||
|
||||
std::string signed_reloc(const RecompPort::InstructionContext& context) {
|
||||
std::string signed_reloc(const N64Recomp::InstructionContext& context) {
|
||||
return "(int16_t)" + unsigned_reloc(context);
|
||||
}
|
||||
|
||||
void RecompPort::CGenerator::get_operand_string(Operand operand, UnaryOpType operation, const InstructionContext& context, std::string& operand_string) const {
|
||||
void N64Recomp::CGenerator::get_operand_string(Operand operand, UnaryOpType operation, const InstructionContext& context, std::string& operand_string) const {
|
||||
switch (operand) {
|
||||
case Operand::Rd:
|
||||
operand_string = gpr_to_string(context.rd);
|
||||
|
|
@ -172,7 +172,7 @@ void RecompPort::CGenerator::get_operand_string(Operand operand, UnaryOpType ope
|
|||
operand_string = fpr_u64_to_string(context.ft);
|
||||
break;
|
||||
case Operand::ImmU16:
|
||||
if (context.reloc_type != RecompPort::RelocType::R_MIPS_NONE) {
|
||||
if (context.reloc_type != N64Recomp::RelocType::R_MIPS_NONE) {
|
||||
operand_string = unsigned_reloc(context);
|
||||
}
|
||||
else {
|
||||
|
|
@ -180,7 +180,7 @@ void RecompPort::CGenerator::get_operand_string(Operand operand, UnaryOpType ope
|
|||
}
|
||||
break;
|
||||
case Operand::ImmS16:
|
||||
if (context.reloc_type != RecompPort::RelocType::R_MIPS_NONE) {
|
||||
if (context.reloc_type != N64Recomp::RelocType::R_MIPS_NONE) {
|
||||
operand_string = signed_reloc(context);
|
||||
}
|
||||
else {
|
||||
|
|
@ -311,12 +311,12 @@ void RecompPort::CGenerator::get_operand_string(Operand operand, UnaryOpType ope
|
|||
}
|
||||
}
|
||||
|
||||
void RecompPort::CGenerator::get_notation(BinaryOpType op_type, std::string& func_string, std::string& infix_string) const {
|
||||
void N64Recomp::CGenerator::get_notation(BinaryOpType op_type, std::string& func_string, std::string& infix_string) const {
|
||||
func_string = c_op_fields[static_cast<size_t>(op_type)].func_string;
|
||||
infix_string = c_op_fields[static_cast<size_t>(op_type)].infix_string;
|
||||
}
|
||||
|
||||
void RecompPort::CGenerator::get_binary_expr_string(BinaryOpType type, const BinaryOperands& operands, const InstructionContext& ctx, const std::string& output, std::string& expr_string) const {
|
||||
void N64Recomp::CGenerator::get_binary_expr_string(BinaryOpType type, const BinaryOperands& operands, const InstructionContext& ctx, const std::string& output, std::string& expr_string) const {
|
||||
thread_local std::string input_a{};
|
||||
thread_local std::string input_b{};
|
||||
thread_local std::string func_string{};
|
||||
|
|
@ -363,7 +363,7 @@ void RecompPort::CGenerator::get_binary_expr_string(BinaryOpType type, const Bin
|
|||
}
|
||||
}
|
||||
|
||||
void RecompPort::CGenerator::emit_branch_condition(std::ostream& output_file, const ConditionalBranchOp& op, const InstructionContext& ctx) const {
|
||||
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.
|
||||
thread_local std::string expr_string{};
|
||||
|
|
@ -371,19 +371,19 @@ void RecompPort::CGenerator::emit_branch_condition(std::ostream& output_file, co
|
|||
fmt::print(output_file, "if ({}) {{\n", expr_string);
|
||||
}
|
||||
|
||||
void RecompPort::CGenerator::emit_branch_close(std::ostream& output_file) const {
|
||||
void N64Recomp::CGenerator::emit_branch_close(std::ostream& output_file) const {
|
||||
fmt::print(output_file, " }}\n");
|
||||
}
|
||||
|
||||
void RecompPort::CGenerator::emit_check_fr(std::ostream& output_file, int fpr) const {
|
||||
void N64Recomp::CGenerator::emit_check_fr(std::ostream& output_file, int fpr) const {
|
||||
fmt::print(output_file, "CHECK_FR(ctx, {});\n ", fpr);
|
||||
}
|
||||
|
||||
void RecompPort::CGenerator::emit_check_nan(std::ostream& output_file, int fpr, bool is_double) const {
|
||||
void N64Recomp::CGenerator::emit_check_nan(std::ostream& output_file, int fpr, bool is_double) const {
|
||||
fmt::print(output_file, "NAN_CHECK(ctx->f{}.{}); ", fpr, is_double ? "d" : "fl");
|
||||
}
|
||||
|
||||
void RecompPort::CGenerator::process_binary_op(std::ostream& output_file, const BinaryOp& op, const InstructionContext& ctx) const {
|
||||
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.
|
||||
thread_local std::string output{};
|
||||
|
|
@ -393,7 +393,7 @@ void RecompPort::CGenerator::process_binary_op(std::ostream& output_file, const
|
|||
fmt::print(output_file, "{} = {};\n", output, expression);
|
||||
}
|
||||
|
||||
void RecompPort::CGenerator::process_unary_op(std::ostream& output_file, const UnaryOp& op, const InstructionContext& ctx) const {
|
||||
void N64Recomp::CGenerator::process_unary_op(std::ostream& output_file, const UnaryOp& 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.
|
||||
thread_local std::string output{};
|
||||
|
|
@ -404,7 +404,7 @@ void RecompPort::CGenerator::process_unary_op(std::ostream& output_file, const U
|
|||
fmt::print(output_file, "{} = {};\n", output, input);
|
||||
}
|
||||
|
||||
void RecompPort::CGenerator::process_store_op(std::ostream& output_file, const StoreOp& op, const InstructionContext& ctx) const {
|
||||
void N64Recomp::CGenerator::process_store_op(std::ostream& output_file, const StoreOp& 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.
|
||||
thread_local std::string base_str{};
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include <toml++/toml.hpp>
|
||||
#include "fmt/format.h"
|
||||
#include "config.h"
|
||||
#include "recomp_port.h"
|
||||
#include "n64recomp.h"
|
||||
|
||||
std::filesystem::path concat_if_not_empty(const std::filesystem::path& parent, const std::filesystem::path& child) {
|
||||
if (!child.empty()) {
|
||||
|
|
@ -12,8 +12,8 @@ std::filesystem::path concat_if_not_empty(const std::filesystem::path& parent, c
|
|||
return child;
|
||||
}
|
||||
|
||||
std::vector<RecompPort::ManualFunction> get_manual_funcs(const toml::array* manual_funcs_array) {
|
||||
std::vector<RecompPort::ManualFunction> ret;
|
||||
std::vector<N64Recomp::ManualFunction> get_manual_funcs(const toml::array* manual_funcs_array) {
|
||||
std::vector<N64Recomp::ManualFunction> ret;
|
||||
|
||||
// Reserve room for all the funcs in the map.
|
||||
ret.reserve(manual_funcs_array->size());
|
||||
|
|
@ -104,8 +104,8 @@ std::vector<std::string> get_ignored_funcs(const toml::table* patches_data) {
|
|||
return ignored_funcs;
|
||||
}
|
||||
|
||||
std::vector<RecompPort::FunctionSize> get_func_sizes(const toml::table* patches_data) {
|
||||
std::vector<RecompPort::FunctionSize> func_sizes{};
|
||||
std::vector<N64Recomp::FunctionSize> get_func_sizes(const toml::table* patches_data) {
|
||||
std::vector<N64Recomp::FunctionSize> func_sizes{};
|
||||
|
||||
// Check if the func size array exists.
|
||||
const toml::node_view funcs_data = (*patches_data)["function_sizes"];
|
||||
|
|
@ -143,8 +143,8 @@ std::vector<RecompPort::FunctionSize> get_func_sizes(const toml::table* patches_
|
|||
return func_sizes;
|
||||
}
|
||||
|
||||
std::vector<RecompPort::InstructionPatch> get_instruction_patches(const toml::table* patches_data) {
|
||||
std::vector<RecompPort::InstructionPatch> ret;
|
||||
std::vector<N64Recomp::InstructionPatch> get_instruction_patches(const toml::table* patches_data) {
|
||||
std::vector<N64Recomp::InstructionPatch> ret;
|
||||
|
||||
// Check if the instruction patch array exists.
|
||||
const toml::node_view insn_patch_data = (*patches_data)["instruction"];
|
||||
|
|
@ -172,7 +172,7 @@ std::vector<RecompPort::InstructionPatch> get_instruction_patches(const toml::ta
|
|||
throw toml::parse_error("Instruction patch is not word-aligned", el.source());
|
||||
}
|
||||
|
||||
ret.push_back(RecompPort::InstructionPatch{
|
||||
ret.push_back(N64Recomp::InstructionPatch{
|
||||
.func_name = func_name.value(),
|
||||
.vram = (int32_t)vram.value(),
|
||||
.value = value.value(),
|
||||
|
|
@ -187,8 +187,8 @@ std::vector<RecompPort::InstructionPatch> get_instruction_patches(const toml::ta
|
|||
return ret;
|
||||
}
|
||||
|
||||
std::vector<RecompPort::FunctionHook> get_function_hooks(const toml::table* patches_data) {
|
||||
std::vector<RecompPort::FunctionHook> ret;
|
||||
std::vector<N64Recomp::FunctionHook> get_function_hooks(const toml::table* patches_data) {
|
||||
std::vector<N64Recomp::FunctionHook> ret;
|
||||
|
||||
// Check if the function hook array exists.
|
||||
const toml::node_view func_hook_data = (*patches_data)["hook"];
|
||||
|
|
@ -216,7 +216,7 @@ std::vector<RecompPort::FunctionHook> get_function_hooks(const toml::table* patc
|
|||
throw toml::parse_error("before_vram is not word-aligned", el.source());
|
||||
}
|
||||
|
||||
ret.push_back(RecompPort::FunctionHook{
|
||||
ret.push_back(N64Recomp::FunctionHook{
|
||||
.func_name = func_name.value(),
|
||||
.before_vram = before_vram.has_value() ? (int32_t)before_vram.value() : 0,
|
||||
.text = text.value(),
|
||||
|
|
@ -231,7 +231,7 @@ std::vector<RecompPort::FunctionHook> get_function_hooks(const toml::table* patc
|
|||
return ret;
|
||||
}
|
||||
|
||||
RecompPort::Config::Config(const char* path) {
|
||||
N64Recomp::Config::Config(const char* path) {
|
||||
// Start this config out as bad so that it has to finish parsing without errors to be good.
|
||||
entrypoint = 0;
|
||||
bad = true;
|
||||
|
|
@ -418,27 +418,27 @@ RecompPort::Config::Config(const char* path) {
|
|||
bad = false;
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, RecompPort::RelocType> reloc_type_name_map {
|
||||
{ "R_MIPS_NONE", RecompPort::RelocType::R_MIPS_NONE },
|
||||
{ "R_MIPS_16", RecompPort::RelocType::R_MIPS_16 },
|
||||
{ "R_MIPS_32", RecompPort::RelocType::R_MIPS_32 },
|
||||
{ "R_MIPS_REL32", RecompPort::RelocType::R_MIPS_REL32 },
|
||||
{ "R_MIPS_26", RecompPort::RelocType::R_MIPS_26 },
|
||||
{ "R_MIPS_HI16", RecompPort::RelocType::R_MIPS_HI16 },
|
||||
{ "R_MIPS_LO16", RecompPort::RelocType::R_MIPS_LO16 },
|
||||
{ "R_MIPS_GPREL16", RecompPort::RelocType::R_MIPS_GPREL16 },
|
||||
const std::unordered_map<std::string, N64Recomp::RelocType> reloc_type_name_map {
|
||||
{ "R_MIPS_NONE", N64Recomp::RelocType::R_MIPS_NONE },
|
||||
{ "R_MIPS_16", N64Recomp::RelocType::R_MIPS_16 },
|
||||
{ "R_MIPS_32", N64Recomp::RelocType::R_MIPS_32 },
|
||||
{ "R_MIPS_REL32", N64Recomp::RelocType::R_MIPS_REL32 },
|
||||
{ "R_MIPS_26", N64Recomp::RelocType::R_MIPS_26 },
|
||||
{ "R_MIPS_HI16", N64Recomp::RelocType::R_MIPS_HI16 },
|
||||
{ "R_MIPS_LO16", N64Recomp::RelocType::R_MIPS_LO16 },
|
||||
{ "R_MIPS_GPREL16", N64Recomp::RelocType::R_MIPS_GPREL16 },
|
||||
};
|
||||
|
||||
RecompPort::RelocType reloc_type_from_name(const std::string& reloc_type_name) {
|
||||
N64Recomp::RelocType reloc_type_from_name(const std::string& reloc_type_name) {
|
||||
auto find_it = reloc_type_name_map.find(reloc_type_name);
|
||||
if (find_it != reloc_type_name_map.end()) {
|
||||
return find_it->second;
|
||||
}
|
||||
return RecompPort::RelocType::R_MIPS_NONE;
|
||||
return N64Recomp::RelocType::R_MIPS_NONE;
|
||||
}
|
||||
|
||||
bool RecompPort::Context::from_symbol_file(const std::filesystem::path& symbol_file_path, std::vector<uint8_t>&& rom, RecompPort::Context& out, bool with_relocs) {
|
||||
RecompPort::Context ret{};
|
||||
bool N64Recomp::Context::from_symbol_file(const std::filesystem::path& symbol_file_path, std::vector<uint8_t>&& rom, N64Recomp::Context& out, bool with_relocs) {
|
||||
N64Recomp::Context ret{};
|
||||
|
||||
try {
|
||||
const toml::table config_data = toml::parse_file(symbol_file_path.u8string());
|
||||
|
|
@ -592,15 +592,15 @@ bool RecompPort::Context::from_symbol_file(const std::filesystem::path& symbol_f
|
|||
return true;
|
||||
}
|
||||
|
||||
void RecompPort::Context::import_reference_context(const RecompPort::Context& reference_context) {
|
||||
void N64Recomp::Context::import_reference_context(const N64Recomp::Context& reference_context) {
|
||||
reference_sections.resize(reference_context.sections.size());
|
||||
reference_symbols.reserve(reference_context.functions.size());
|
||||
reference_symbol_names.reserve(reference_context.functions.size());
|
||||
|
||||
// Copy the reference context's sections into the real context's reference sections.
|
||||
for (size_t section_index = 0; section_index < reference_context.sections.size(); section_index++) {
|
||||
const RecompPort::Section& section_in = reference_context.sections[section_index];
|
||||
RecompPort::ReferenceSection& section_out = reference_sections[section_index];
|
||||
const N64Recomp::Section& section_in = reference_context.sections[section_index];
|
||||
N64Recomp::ReferenceSection& section_out = reference_sections[section_index];
|
||||
|
||||
section_out.rom_addr = section_in.rom_addr;
|
||||
section_out.ram_addr = section_in.ram_addr;
|
||||
|
|
@ -609,12 +609,12 @@ void RecompPort::Context::import_reference_context(const RecompPort::Context& re
|
|||
}
|
||||
|
||||
// Copy the functions from the reference context into the reference context's function map.
|
||||
for (const RecompPort::Function& func_in: reference_context.functions) {
|
||||
const RecompPort::Section& func_section = reference_context.sections[func_in.section_index];
|
||||
for (const N64Recomp::Function& func_in: reference_context.functions) {
|
||||
const N64Recomp::Section& func_section = reference_context.sections[func_in.section_index];
|
||||
|
||||
reference_symbols_by_name.emplace(func_in.name, reference_symbols.size());
|
||||
|
||||
reference_symbols.emplace_back(RecompPort::ReferenceSymbol{
|
||||
reference_symbols.emplace_back(N64Recomp::ReferenceSymbol{
|
||||
.section_index = func_in.section_index,
|
||||
.section_offset = func_in.vram - static_cast<uint32_t>(func_section.ram_addr),
|
||||
.is_function = true
|
||||
|
|
@ -624,7 +624,7 @@ void RecompPort::Context::import_reference_context(const RecompPort::Context& re
|
|||
}
|
||||
|
||||
// Reads a data symbol file and adds its contents into this context's reference data symbols.
|
||||
bool RecompPort::Context::read_data_reference_syms(const std::filesystem::path& data_syms_file_path) {
|
||||
bool N64Recomp::Context::read_data_reference_syms(const std::filesystem::path& data_syms_file_path) {
|
||||
try {
|
||||
const toml::table data_syms_file_data = toml::parse_file(data_syms_file_path.u8string());
|
||||
const toml::node_view data_sections_value = data_syms_file_data["section"];
|
||||
|
|
@ -655,7 +655,7 @@ bool RecompPort::Context::read_data_reference_syms(const std::filesystem::path&
|
|||
|
||||
uint16_t ref_section_index;
|
||||
if (!rom_addr.has_value()) {
|
||||
ref_section_index = RecompPort::SectionAbsolute; // Non-relocatable bss section or absolute symbols, mark this as an absolute symbol
|
||||
ref_section_index = N64Recomp::SectionAbsolute; // Non-relocatable bss section or absolute symbols, mark this as an absolute symbol
|
||||
}
|
||||
else if (rom_addr.value() > 0xFFFFFFFF) {
|
||||
throw toml::parse_error("Section has invalid ROM address", el.source());
|
||||
|
|
@ -667,7 +667,7 @@ bool RecompPort::Context::read_data_reference_syms(const std::filesystem::path&
|
|||
ref_section_index = find_section_it->second;
|
||||
}
|
||||
else {
|
||||
ref_section_index = RecompPort::SectionAbsolute; // Not in the function symbol reference file, so this section can be treated as non-relocatable.
|
||||
ref_section_index = N64Recomp::SectionAbsolute; // Not in the function symbol reference file, so this section can be treated as non-relocatable.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -677,10 +677,10 @@ bool RecompPort::Context::read_data_reference_syms(const std::filesystem::path&
|
|||
.size = 0,
|
||||
.relocatable = 0
|
||||
};
|
||||
const ReferenceSection& ref_section = ref_section_index == RecompPort::SectionAbsolute ? dummy_absolute_section : this->reference_sections[ref_section_index];
|
||||
const ReferenceSection& ref_section = ref_section_index == N64Recomp::SectionAbsolute ? dummy_absolute_section : this->reference_sections[ref_section_index];
|
||||
|
||||
// Sanity check this section against the matching one in the function reference symbol file if one exists.
|
||||
if (ref_section_index != RecompPort::SectionAbsolute) {
|
||||
if (ref_section_index != N64Recomp::SectionAbsolute) {
|
||||
if (ref_section.ram_addr != vram_addr.value()) {
|
||||
throw toml::parse_error("Section vram address differs from matching ROM address section in the function symbol reference file", el.source());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
#include <filesystem>
|
||||
#include <vector>
|
||||
|
||||
namespace RecompPort {
|
||||
namespace N64Recomp {
|
||||
struct InstructionPatch {
|
||||
std::string func_name;
|
||||
int32_t vram;
|
||||
|
|
|
|||
91
src/main.cpp
91
src/main.cpp
|
|
@ -10,7 +10,7 @@
|
|||
#include "fmt/format.h"
|
||||
#include "fmt/ostream.h"
|
||||
|
||||
#include "recomp_port.h"
|
||||
#include "n64recomp.h"
|
||||
#include "config.h"
|
||||
#include <set>
|
||||
|
||||
|
|
@ -680,7 +680,7 @@ struct DataSymbol {
|
|||
DataSymbol(uint32_t vram, std::string&& name) : vram(vram), name(std::move(name)) {}
|
||||
};
|
||||
|
||||
bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, ELFIO::section* symtab_section, uint32_t entrypoint, bool has_entrypoint, bool use_absolute_symbols, bool dumping_context, std::unordered_map<uint16_t, std::vector<DataSymbol>>& data_syms) {
|
||||
bool read_symbols(N64Recomp::Context& context, const ELFIO::elfio& elf_file, ELFIO::section* symtab_section, uint32_t entrypoint, bool has_entrypoint, bool use_absolute_symbols, bool dumping_context, std::unordered_map<uint16_t, std::vector<DataSymbol>>& data_syms) {
|
||||
bool found_entrypoint_func = false;
|
||||
ELFIO::symbol_section_accessor symbols{ elf_file, symtab_section };
|
||||
fmt::print("Num symbols: {}\n", symbols.get_symbols_num());
|
||||
|
|
@ -692,7 +692,7 @@ bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, EL
|
|||
if (dumping_context) {
|
||||
// Process bss and reloc sections
|
||||
for (size_t cur_section_index = 0; cur_section_index < context.sections.size(); cur_section_index++) {
|
||||
const RecompPort::Section& cur_section = context.sections[cur_section_index];
|
||||
const N64Recomp::Section& cur_section = context.sections[cur_section_index];
|
||||
// Check if a bss section was found that corresponds with this section.
|
||||
if (cur_section.bss_section_index != (uint16_t)-1) {
|
||||
bss_section_to_target_section[cur_section.bss_section_index] = cur_section_index;
|
||||
|
|
@ -844,7 +844,7 @@ bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, EL
|
|||
// Place this symbol in the absolute symbol list if it's in the absolute section.
|
||||
uint16_t target_section_index = section_index;
|
||||
if (section_index == ELFIO::SHN_ABS) {
|
||||
target_section_index = RecompPort::SectionAbsolute;
|
||||
target_section_index = N64Recomp::SectionAbsolute;
|
||||
}
|
||||
else if (section_index >= context.sections.size()) {
|
||||
fmt::print("Symbol \"{}\" not in a valid section ({})\n", name, section_index);
|
||||
|
|
@ -867,7 +867,7 @@ bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, EL
|
|||
return found_entrypoint_func;
|
||||
}
|
||||
|
||||
void add_manual_functions(RecompPort::Context& context, const ELFIO::elfio& elf_file, const std::vector<RecompPort::ManualFunction>& manual_funcs) {
|
||||
void add_manual_functions(N64Recomp::Context& context, const ELFIO::elfio& elf_file, const std::vector<N64Recomp::ManualFunction>& manual_funcs) {
|
||||
auto exit_failure = [](const std::string& error_str) {
|
||||
fmt::vprint(stderr, error_str, fmt::make_format_args());
|
||||
std::exit(EXIT_FAILURE);
|
||||
|
|
@ -881,7 +881,7 @@ void add_manual_functions(RecompPort::Context& context, const ELFIO::elfio& elf_
|
|||
section_indices_by_name.emplace(context.sections[i].name, i);
|
||||
}
|
||||
|
||||
for (const RecompPort::ManualFunction& cur_func_def : manual_funcs) {
|
||||
for (const N64Recomp::ManualFunction& cur_func_def : manual_funcs) {
|
||||
const auto section_find_it = section_indices_by_name.find(cur_func_def.section_name);
|
||||
if (section_find_it == section_indices_by_name.end()) {
|
||||
exit_failure(fmt::format("Manual function {} specified with section {}, which doesn't exist!\n", cur_func_def.func_name, cur_func_def.section_name));
|
||||
|
|
@ -946,7 +946,7 @@ std::optional<size_t> get_segment(const std::vector<SegmentEntry>& segments, ELF
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
ELFIO::section* read_sections(RecompPort::Context& context, const RecompPort::Config& config, const ELFIO::elfio& elf_file) {
|
||||
ELFIO::section* read_sections(N64Recomp::Context& context, const N64Recomp::Config& config, const ELFIO::elfio& elf_file) {
|
||||
ELFIO::section* symtab_section = nullptr;
|
||||
std::vector<SegmentEntry> segments{};
|
||||
segments.resize(elf_file.segments.size());
|
||||
|
|
@ -1076,7 +1076,7 @@ ELFIO::section* read_sections(RecompPort::Context& context, const RecompPort::Co
|
|||
|
||||
// Process bss and reloc sections
|
||||
for (size_t section_index = 0; section_index < context.sections.size(); section_index++) {
|
||||
RecompPort::Section& section_out = context.sections[section_index];
|
||||
N64Recomp::Section& section_out = context.sections[section_index];
|
||||
// Check if a bss section was found that corresponds with this section
|
||||
auto bss_find = bss_sections_by_name.find(section_out.name);
|
||||
if (bss_find != bss_sections_by_name.end()) {
|
||||
|
|
@ -1106,7 +1106,7 @@ ELFIO::section* read_sections(RecompPort::Context& context, const RecompPort::Co
|
|||
ELFIO::Elf_Sxword bad_rel_addend; // Addends aren't encoded in the reloc, so ignore this one
|
||||
rel_accessor.get_entry(i, rel_offset, rel_symbol, rel_type, bad_rel_addend);
|
||||
|
||||
RecompPort::Reloc& reloc_out = section_out.relocs[i];
|
||||
N64Recomp::Reloc& reloc_out = section_out.relocs[i];
|
||||
|
||||
// Get the real full_immediate by extracting the immediate from the instruction
|
||||
uint32_t reloc_rom_addr = section_out.rom_addr + rel_offset - section_out.ram_addr;
|
||||
|
|
@ -1116,7 +1116,7 @@ ELFIO::section* read_sections(RecompPort::Context& context, const RecompPort::Co
|
|||
|
||||
reloc_out.address = rel_offset;
|
||||
reloc_out.symbol_index = rel_symbol;
|
||||
reloc_out.type = static_cast<RecompPort::RelocType>(rel_type);
|
||||
reloc_out.type = static_cast<N64Recomp::RelocType>(rel_type);
|
||||
|
||||
std::string rel_symbol_name;
|
||||
ELFIO::Elf64_Addr rel_symbol_value;
|
||||
|
|
@ -1151,11 +1151,11 @@ ELFIO::section* read_sections(RecompPort::Context& context, const RecompPort::Co
|
|||
|
||||
bool target_section_relocatable = false;
|
||||
|
||||
if (reloc_out.target_section != RecompPort::SectionAbsolute && context.reference_sections[reloc_out.target_section].relocatable) {
|
||||
if (reloc_out.target_section != N64Recomp::SectionAbsolute && context.reference_sections[reloc_out.target_section].relocatable) {
|
||||
target_section_relocatable = true;
|
||||
}
|
||||
|
||||
if (reloc_out.type == RecompPort::RelocType::R_MIPS_32 && target_section_relocatable) {
|
||||
if (reloc_out.type == N64Recomp::RelocType::R_MIPS_32 && target_section_relocatable) {
|
||||
fmt::print(stderr, "Cannot reference {} in a statically initialized variable as it's defined in a relocatable section!\n",
|
||||
rel_symbol_name);
|
||||
return nullptr;
|
||||
|
|
@ -1167,7 +1167,7 @@ ELFIO::section* read_sections(RecompPort::Context& context, const RecompPort::Co
|
|||
}
|
||||
|
||||
// Reloc pairing, see MIPS System V ABI documentation page 4-18 (https://refspecs.linuxfoundation.org/elf/mipsabi.pdf)
|
||||
if (reloc_out.type == RecompPort::RelocType::R_MIPS_LO16) {
|
||||
if (reloc_out.type == N64Recomp::RelocType::R_MIPS_LO16) {
|
||||
uint32_t rel_immediate = instr.getProcessedImmediate();
|
||||
uint32_t full_immediate = (prev_hi_immediate << 16) + (int16_t)rel_immediate;
|
||||
reloc_out.section_offset = full_immediate + rel_symbol_offset - rel_section_vram;
|
||||
|
|
@ -1215,7 +1215,7 @@ ELFIO::section* read_sections(RecompPort::Context& context, const RecompPort::Co
|
|||
prev_lo = false;
|
||||
}
|
||||
|
||||
if (reloc_out.type == RecompPort::RelocType::R_MIPS_HI16) {
|
||||
if (reloc_out.type == N64Recomp::RelocType::R_MIPS_HI16) {
|
||||
uint32_t rel_immediate = instr.getProcessedImmediate();
|
||||
prev_hi = true;
|
||||
prev_hi_immediate = rel_immediate;
|
||||
|
|
@ -1224,7 +1224,7 @@ ELFIO::section* read_sections(RecompPort::Context& context, const RecompPort::Co
|
|||
prev_hi = false;
|
||||
}
|
||||
|
||||
if (reloc_out.type == RecompPort::RelocType::R_MIPS_32) {
|
||||
if (reloc_out.type == N64Recomp::RelocType::R_MIPS_32) {
|
||||
// The reloc addend is just the existing word before relocation, so the section offset can just be the symbol's section offset.
|
||||
// Incorporating the addend will be handled at load-time.
|
||||
reloc_out.section_offset = rel_symbol_offset;
|
||||
|
|
@ -1232,7 +1232,7 @@ ELFIO::section* read_sections(RecompPort::Context& context, const RecompPort::Co
|
|||
|
||||
if (reloc_out.reference_symbol) {
|
||||
uint32_t reloc_target_section_addr = 0;
|
||||
if (reloc_out.target_section != RecompPort::SectionAbsolute) {
|
||||
if (reloc_out.target_section != N64Recomp::SectionAbsolute) {
|
||||
reloc_target_section_addr = context.reference_sections[reloc_out.target_section].ram_addr;
|
||||
}
|
||||
// Patch the word in the ROM to incorporate the symbol's value.
|
||||
|
|
@ -1241,7 +1241,7 @@ ELFIO::section* read_sections(RecompPort::Context& context, const RecompPort::Co
|
|||
}
|
||||
}
|
||||
|
||||
if (reloc_out.type == RecompPort::RelocType::R_MIPS_26) {
|
||||
if (reloc_out.type == N64Recomp::RelocType::R_MIPS_26) {
|
||||
uint32_t rel_immediate = instr.getProcessedImmediate();
|
||||
reloc_out.section_offset = rel_immediate + rel_symbol_offset;
|
||||
}
|
||||
|
|
@ -1252,7 +1252,7 @@ ELFIO::section* read_sections(RecompPort::Context& context, const RecompPort::Co
|
|||
// This is safe to do as the entire full_immediate in present in relocs due to the pairing that was done earlier, so the HI16 does not
|
||||
// need to directly preceed the matching LO16 anymore.
|
||||
std::sort(section_out.relocs.begin(), section_out.relocs.end(),
|
||||
[](const RecompPort::Reloc& a, const RecompPort::Reloc& b) {
|
||||
[](const N64Recomp::Reloc& a, const N64Recomp::Reloc& b) {
|
||||
return a.address < b.address;
|
||||
}
|
||||
);
|
||||
|
|
@ -1271,22 +1271,22 @@ for_each_if(Iterator begin, Iterator end, Pred p, Operation op) {
|
|||
}
|
||||
}
|
||||
|
||||
void analyze_sections(RecompPort::Context& context, const ELFIO::elfio& elf_file) {
|
||||
std::vector<RecompPort::Section*> executable_sections{};
|
||||
void analyze_sections(N64Recomp::Context& context, const ELFIO::elfio& elf_file) {
|
||||
std::vector<N64Recomp::Section*> executable_sections{};
|
||||
|
||||
executable_sections.reserve(context.executable_section_count);
|
||||
|
||||
for_each_if(context.sections.begin(), context.sections.end(),
|
||||
[](const RecompPort::Section& section) {
|
||||
[](const N64Recomp::Section& section) {
|
||||
return section.executable && section.rom_addr >= 0x1000;
|
||||
},
|
||||
[&](RecompPort::Section& section) {
|
||||
[&](N64Recomp::Section& section) {
|
||||
executable_sections.push_back(§ion);
|
||||
}
|
||||
);
|
||||
|
||||
std::sort(executable_sections.begin(), executable_sections.end(),
|
||||
[](const RecompPort::Section* a, const RecompPort::Section* b) {
|
||||
[](const N64Recomp::Section* a, const N64Recomp::Section* b) {
|
||||
return a->ram_addr < b->ram_addr;
|
||||
}
|
||||
);
|
||||
|
|
@ -1331,7 +1331,7 @@ bool compare_files(const std::filesystem::path& file1_path, const std::filesyste
|
|||
return std::equal(begin1, std::istreambuf_iterator<char>(), begin2); //Second argument is end-of-range iterator
|
||||
}
|
||||
|
||||
bool recompile_single_function(const RecompPort::Context& context, const RecompPort::Function& func, const std::string& recomp_include, const std::filesystem::path& output_path, std::span<std::vector<uint32_t>> static_funcs_out) {
|
||||
bool recompile_single_function(const N64Recomp::Context& context, const N64Recomp::Function& func, const std::string& recomp_include, const std::filesystem::path& output_path, std::span<std::vector<uint32_t>> static_funcs_out) {
|
||||
// Open the temporary output file
|
||||
std::filesystem::path temp_path = output_path;
|
||||
temp_path.replace_extension(".tmp");
|
||||
|
|
@ -1341,7 +1341,7 @@ bool recompile_single_function(const RecompPort::Context& context, const RecompP
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!RecompPort::recompile_function(context, func, recomp_include, output_file, static_funcs_out, true)) {
|
||||
if (!N64Recomp::recompile_function(context, func, recomp_include, output_file, static_funcs_out, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1371,7 +1371,7 @@ std::vector<std::string> reloc_names {
|
|||
"R_MIPS_GPREL16",
|
||||
};
|
||||
|
||||
void dump_context(const RecompPort::Context& context, const std::unordered_map<uint16_t, std::vector<DataSymbol>>& data_syms, const std::filesystem::path& func_path, const std::filesystem::path& data_path) {
|
||||
void dump_context(const N64Recomp::Context& context, const std::unordered_map<uint16_t, std::vector<DataSymbol>>& data_syms, const std::filesystem::path& func_path, const std::filesystem::path& data_path) {
|
||||
std::ofstream func_context_file {func_path};
|
||||
std::ofstream data_context_file {data_path};
|
||||
|
||||
|
|
@ -1401,7 +1401,7 @@ void dump_context(const RecompPort::Context& context, const std::unordered_map<u
|
|||
};
|
||||
|
||||
for (size_t section_index = 0; section_index < context.sections.size(); section_index++) {
|
||||
const RecompPort::Section& section = context.sections[section_index];
|
||||
const N64Recomp::Section& section = context.sections[section_index];
|
||||
const std::vector<size_t>& section_funcs = context.section_functions[section_index];
|
||||
if (!section_funcs.empty()) {
|
||||
print_section(func_context_file, section.name, section.rom_addr, section.ram_addr, section.size);
|
||||
|
|
@ -1410,10 +1410,10 @@ void dump_context(const RecompPort::Context& context, const std::unordered_map<u
|
|||
if (!section.relocs.empty()) {
|
||||
fmt::print(func_context_file, "relocs = [\n");
|
||||
|
||||
for (const RecompPort::Reloc& reloc : section.relocs) {
|
||||
for (const N64Recomp::Reloc& reloc : section.relocs) {
|
||||
if (reloc.target_section == section_index || reloc.target_section == section.bss_section_index) {
|
||||
// TODO allow emitting MIPS32 relocs for specific sections via a toml option for TLB mapping support.
|
||||
if (reloc.type == RecompPort::RelocType::R_MIPS_HI16 || reloc.type == RecompPort::RelocType::R_MIPS_LO16) {
|
||||
if (reloc.type == N64Recomp::RelocType::R_MIPS_HI16 || reloc.type == N64Recomp::RelocType::R_MIPS_LO16) {
|
||||
fmt::print(func_context_file, " {{ type = \"{}\", vram = 0x{:08X}, target_vram = 0x{:08X} }},\n",
|
||||
reloc_names[static_cast<int>(reloc.type)], reloc.address, reloc.section_offset + section.ram_addr);
|
||||
}
|
||||
|
|
@ -1427,7 +1427,7 @@ void dump_context(const RecompPort::Context& context, const std::unordered_map<u
|
|||
fmt::print(func_context_file, "functions = [\n");
|
||||
|
||||
for (const size_t& function_index : section_funcs) {
|
||||
const RecompPort::Function& func = context.functions[function_index];
|
||||
const N64Recomp::Function& func = context.functions[function_index];
|
||||
fmt::print(func_context_file, " {{ name = \"{}\", vram = 0x{:08X}, size = 0x{:X} }},\n",
|
||||
func.name, func.vram, func.words.size() * sizeof(func.words[0]));
|
||||
}
|
||||
|
|
@ -1483,7 +1483,7 @@ static std::vector<uint8_t> read_file(const std::filesystem::path& path) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void setup_context_for_elf(RecompPort::Context& context, const ELFIO::elfio& elf_file) {
|
||||
static void setup_context_for_elf(N64Recomp::Context& context, const ELFIO::elfio& elf_file) {
|
||||
context.sections.resize(elf_file.sections.size());
|
||||
context.section_functions.resize(elf_file.sections.size());
|
||||
context.functions.reserve(1024);
|
||||
|
|
@ -1509,7 +1509,7 @@ int main(int argc, char** argv) {
|
|||
|
||||
const char* config_path = argv[1];
|
||||
|
||||
RecompPort::Config config{ config_path };
|
||||
N64Recomp::Config config{ config_path };
|
||||
if (!config.good()) {
|
||||
exit_failure(fmt::format("Failed to load config file: {}\n", config_path));
|
||||
}
|
||||
|
|
@ -1531,7 +1531,7 @@ int main(int argc, char** argv) {
|
|||
std::unordered_set<std::string> relocatable_sections{};
|
||||
relocatable_sections.insert(relocatable_sections_ordered.begin(), relocatable_sections_ordered.end());
|
||||
|
||||
RecompPort::Context context{};
|
||||
N64Recomp::Context context{};
|
||||
|
||||
if (!config.elf_path.empty() && !config.symbols_file_path.empty()) {
|
||||
exit_failure("Config file cannot provide both an elf and a symbols file\n");
|
||||
|
|
@ -1561,8 +1561,8 @@ int main(int argc, char** argv) {
|
|||
{
|
||||
// Create a new temporary context to read the function reference symbol file into, since it's the same format as the recompilation symbol file.
|
||||
std::vector<uint8_t> dummy_rom{};
|
||||
RecompPort::Context reference_context{};
|
||||
if (!RecompPort::Context::from_symbol_file(config.func_reference_syms_file_path, std::move(dummy_rom), reference_context, false)) {
|
||||
N64Recomp::Context reference_context{};
|
||||
if (!N64Recomp::Context::from_symbol_file(config.func_reference_syms_file_path, std::move(dummy_rom), reference_context, false)) {
|
||||
exit_failure("Failed to load provided function reference symbol file\n");
|
||||
}
|
||||
|
||||
|
|
@ -1636,12 +1636,12 @@ int main(int argc, char** argv) {
|
|||
exit_failure("Failed to load ROM file: " + config.rom_file_path.string() + "\n");
|
||||
}
|
||||
|
||||
if (!RecompPort::Context::from_symbol_file(config.symbols_file_path, std::move(rom), context, true)) {
|
||||
if (!N64Recomp::Context::from_symbol_file(config.symbols_file_path, std::move(rom), context, true)) {
|
||||
exit_failure("Failed to load symbols file\n");
|
||||
}
|
||||
|
||||
auto rename_function = [&context](size_t func_index, const std::string& new_name) {
|
||||
RecompPort::Function& func = context.functions[func_index];
|
||||
N64Recomp::Function& func = context.functions[func_index];
|
||||
|
||||
context.functions_by_name.erase(func.name);
|
||||
func.name = new_name;
|
||||
|
|
@ -1649,7 +1649,7 @@ int main(int argc, char** argv) {
|
|||
};
|
||||
|
||||
for (size_t func_index = 0; func_index < context.functions.size(); func_index++) {
|
||||
RecompPort::Function& func = context.functions[func_index];
|
||||
N64Recomp::Function& func = context.functions[func_index];
|
||||
if (reimplemented_funcs.contains(func.name)) {
|
||||
rename_function(func_index, func.name + "_recomp");
|
||||
func.reimplemented = true;
|
||||
|
|
@ -1734,7 +1734,7 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
|
||||
// Apply any single-instruction patches.
|
||||
for (const RecompPort::InstructionPatch& patch : config.instruction_patches) {
|
||||
for (const N64Recomp::InstructionPatch& patch : config.instruction_patches) {
|
||||
// Check if the specified function exists.
|
||||
auto func_find = context.functions_by_name.find(patch.func_name);
|
||||
if (func_find == context.functions_by_name.end()) {
|
||||
|
|
@ -1743,7 +1743,7 @@ int main(int argc, char** argv) {
|
|||
exit_failure(fmt::format("Function {} has an instruction patch but does not exist!", patch.func_name));
|
||||
}
|
||||
|
||||
RecompPort::Function& func = context.functions[func_find->second];
|
||||
N64Recomp::Function& func = context.functions[func_find->second];
|
||||
int32_t func_vram = func.vram;
|
||||
|
||||
// Check that the function actually contains this vram address.
|
||||
|
|
@ -1757,7 +1757,7 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
|
||||
// Apply any function hooks.
|
||||
for (const RecompPort::FunctionHook& patch : config.function_hooks) {
|
||||
for (const N64Recomp::FunctionHook& patch : config.function_hooks) {
|
||||
// Check if the specified function exists.
|
||||
auto func_find = context.functions_by_name.find(patch.func_name);
|
||||
if (func_find == context.functions_by_name.end()) {
|
||||
|
|
@ -1766,7 +1766,7 @@ int main(int argc, char** argv) {
|
|||
exit_failure(fmt::format("Function {} has a function hook but does not exist!", patch.func_name));
|
||||
}
|
||||
|
||||
RecompPort::Function& func = context.functions[func_find->second];
|
||||
N64Recomp::Function& func = context.functions[func_find->second];
|
||||
int32_t func_vram = func.vram;
|
||||
|
||||
// Check that the function actually contains this vram address.
|
||||
|
|
@ -1829,7 +1829,7 @@ int main(int argc, char** argv) {
|
|||
"void {}(uint8_t* rdram, recomp_context* ctx);\n", func.name);
|
||||
bool result;
|
||||
if (config.single_file_output || config.functions_per_output_file > 1) {
|
||||
result = RecompPort::recompile_function(context, func, config.recomp_include, current_output_file, static_funcs_by_section, false);
|
||||
result = N64Recomp::recompile_function(context, func, config.recomp_include, current_output_file, static_funcs_by_section, false);
|
||||
if (!config.single_file_output) {
|
||||
cur_file_function_count++;
|
||||
if (cur_file_function_count >= config.functions_per_output_file) {
|
||||
|
|
@ -1892,7 +1892,7 @@ int main(int argc, char** argv) {
|
|||
std::vector<uint32_t> insn_words((cur_func_end - static_func_addr) / sizeof(uint32_t));
|
||||
insn_words.assign(func_rom_start, func_rom_start + insn_words.size());
|
||||
|
||||
RecompPort::Function func {
|
||||
N64Recomp::Function func {
|
||||
static_func_addr,
|
||||
rom_addr,
|
||||
std::move(insn_words),
|
||||
|
|
@ -1906,9 +1906,8 @@ int main(int argc, char** argv) {
|
|||
|
||||
bool result;
|
||||
size_t prev_num_statics = static_funcs_by_section[func.section_index].size();
|
||||
|
||||
if (config.single_file_output || config.functions_per_output_file > 1) {
|
||||
result = RecompPort::recompile_function(context, func, config.recomp_include, current_output_file, static_funcs_by_section, false);
|
||||
result = N64Recomp::recompile_function(context, func, config.recomp_include, current_output_file, static_funcs_by_section, false);
|
||||
if (!config.single_file_output) {
|
||||
cur_file_function_count++;
|
||||
if (cur_file_function_count >= config.functions_per_output_file) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "operations.h"
|
||||
|
||||
namespace RecompPort {
|
||||
namespace N64Recomp {
|
||||
const std::unordered_map<InstrId, UnaryOp> unary_ops {
|
||||
{ InstrId::cpu_lui, { UnaryOpType::Lui, Operand::Rt, Operand::ImmU16 } },
|
||||
{ InstrId::cpu_mthi, { UnaryOpType::None, Operand::Hi, Operand::Rs } },
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
#include "fmt/format.h"
|
||||
#include "fmt/ostream.h"
|
||||
|
||||
#include "recomp_port.h"
|
||||
#include "n64recomp.h"
|
||||
#include "analysis.h"
|
||||
#include "operations.h"
|
||||
#include "generator.h"
|
||||
|
|
@ -21,9 +21,9 @@ enum class JalResolutionResult {
|
|||
Error
|
||||
};
|
||||
|
||||
JalResolutionResult resolve_jal(const RecompPort::Context& context, size_t cur_section_index, uint32_t target_func_vram, size_t& matched_function_index) {
|
||||
JalResolutionResult resolve_jal(const N64Recomp::Context& context, size_t cur_section_index, uint32_t target_func_vram, size_t& matched_function_index) {
|
||||
// Look for symbols with the target vram address
|
||||
const RecompPort::Section& cur_section = context.sections[cur_section_index];
|
||||
const N64Recomp::Section& cur_section = context.sections[cur_section_index];
|
||||
const auto matching_funcs_find = context.functions_by_vram.find(target_func_vram);
|
||||
uint32_t section_vram_start = cur_section.ram_addr;
|
||||
uint32_t section_vram_end = cur_section.ram_addr + cur_section.size;
|
||||
|
|
@ -110,8 +110,8 @@ std::string_view ctx_gpr_prefix(int reg) {
|
|||
}
|
||||
|
||||
// Major TODO, this function grew very organically and needs to be cleaned up. Ideally, it'll get split up into some sort of lookup table grouped by similar instruction types.
|
||||
bool process_instruction(const RecompPort::Context& context, const RecompPort::Function& func, const RecompPort::FunctionStats& stats, const std::unordered_set<uint32_t>& skipped_insns, size_t instr_index, const std::vector<rabbitizer::InstructionCpu>& instructions, std::ofstream& output_file, bool indent, bool emit_link_branch, int link_branch_index, size_t reloc_index, bool& needs_link_branch, bool& is_branch_likely, std::span<std::vector<uint32_t>> static_funcs_out) {
|
||||
using namespace RecompPort;
|
||||
bool process_instruction(const N64Recomp::Context& context, const N64Recomp::Function& func, const N64Recomp::FunctionStats& stats, const std::unordered_set<uint32_t>& skipped_insns, size_t instr_index, const std::vector<rabbitizer::InstructionCpu>& instructions, std::ofstream& output_file, bool indent, bool emit_link_branch, int link_branch_index, size_t reloc_index, bool& needs_link_branch, bool& is_branch_likely, std::span<std::vector<uint32_t>> static_funcs_out) {
|
||||
using namespace N64Recomp;
|
||||
|
||||
const auto& section = context.sections[func.section_index];
|
||||
const auto& instr = instructions[instr_index];
|
||||
|
|
@ -144,7 +144,7 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::F
|
|||
return true;
|
||||
}
|
||||
|
||||
RecompPort::RelocType reloc_type = RecompPort::RelocType::R_MIPS_NONE;
|
||||
N64Recomp::RelocType reloc_type = N64Recomp::RelocType::R_MIPS_NONE;
|
||||
uint32_t reloc_section = 0;
|
||||
uint32_t reloc_target_section_offset = 0;
|
||||
size_t reloc_reference_symbol = (size_t)-1;
|
||||
|
|
@ -172,31 +172,31 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::F
|
|||
reloc_type = reloc.type;
|
||||
reloc_target_section_offset = reloc.section_offset;
|
||||
// Ignore all relocs that aren't HI16 or LO16.
|
||||
if (reloc_type == RecompPort::RelocType::R_MIPS_HI16 || reloc_type == RecompPort::RelocType::R_MIPS_LO16 || reloc_type == RecompPort::RelocType::R_MIPS_26) {
|
||||
if (reloc_type == N64Recomp::RelocType::R_MIPS_HI16 || reloc_type == N64Recomp::RelocType::R_MIPS_LO16 || reloc_type == N64Recomp::RelocType::R_MIPS_26) {
|
||||
if (reloc.reference_symbol) {
|
||||
reloc_reference_symbol = reloc.symbol_index;
|
||||
static RecompPort::ReferenceSection dummy_section{
|
||||
static N64Recomp::ReferenceSection dummy_section{
|
||||
.rom_addr = 0,
|
||||
.ram_addr = 0,
|
||||
.size = 0,
|
||||
.relocatable = false
|
||||
};
|
||||
const auto& reloc_reference_section = reloc.target_section == RecompPort::SectionAbsolute ? dummy_section : context.reference_sections[reloc.target_section];
|
||||
const auto& reloc_reference_section = reloc.target_section == N64Recomp::SectionAbsolute ? dummy_section : context.reference_sections[reloc.target_section];
|
||||
// Resolve HI16 and LO16 reference symbol relocs to non-relocatable sections by patching the instruction immediate.
|
||||
if (!reloc_reference_section.relocatable && (reloc_type == RecompPort::RelocType::R_MIPS_HI16 || reloc_type == RecompPort::RelocType::R_MIPS_LO16)) {
|
||||
if (!reloc_reference_section.relocatable && (reloc_type == N64Recomp::RelocType::R_MIPS_HI16 || reloc_type == N64Recomp::RelocType::R_MIPS_LO16)) {
|
||||
uint32_t full_immediate = reloc.section_offset + reloc_reference_section.ram_addr;
|
||||
|
||||
if (reloc_type == RecompPort::RelocType::R_MIPS_HI16) {
|
||||
if (reloc_type == N64Recomp::RelocType::R_MIPS_HI16) {
|
||||
imm = (full_immediate >> 16) + ((full_immediate >> 15) & 1);
|
||||
reloc_type = RecompPort::RelocType::R_MIPS_NONE;
|
||||
reloc_type = N64Recomp::RelocType::R_MIPS_NONE;
|
||||
}
|
||||
else if (reloc_type == RecompPort::RelocType::R_MIPS_LO16) {
|
||||
else if (reloc_type == N64Recomp::RelocType::R_MIPS_LO16) {
|
||||
imm = full_immediate & 0xFFFF;
|
||||
reloc_type = RecompPort::RelocType::R_MIPS_NONE;
|
||||
reloc_type = N64Recomp::RelocType::R_MIPS_NONE;
|
||||
}
|
||||
|
||||
// The reloc has been processed, so delete it to none to prevent it getting processed a second time during instruction code generation.
|
||||
reloc_type = RecompPort::RelocType::R_MIPS_NONE;
|
||||
reloc_type = N64Recomp::RelocType::R_MIPS_NONE;
|
||||
reloc_reference_symbol = (size_t)-1;
|
||||
}
|
||||
}
|
||||
|
|
@ -248,7 +248,7 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::F
|
|||
const auto& ref_symbol = context.reference_symbols[reloc_reference_symbol];
|
||||
const std::string& ref_symbol_name = context.reference_symbol_names[reloc_reference_symbol];
|
||||
|
||||
if (reloc_type != RecompPort::RelocType::R_MIPS_26) {
|
||||
if (reloc_type != N64Recomp::RelocType::R_MIPS_26) {
|
||||
fmt::print(stderr, "Unsupported reloc type {} on jal instruction in {}\n", (int)reloc_type, func.name);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -388,12 +388,12 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::F
|
|||
{
|
||||
// Check if this addu belongs to a jump table load
|
||||
auto find_result = std::find_if(stats.jump_tables.begin(), stats.jump_tables.end(),
|
||||
[instr_vram](const RecompPort::JumpTable& jtbl) {
|
||||
[instr_vram](const N64Recomp::JumpTable& jtbl) {
|
||||
return jtbl.addu_vram == instr_vram;
|
||||
});
|
||||
// If so, create a temp to preserve the addend register's value
|
||||
if (find_result != stats.jump_tables.end()) {
|
||||
const RecompPort::JumpTable& cur_jtbl = *find_result;
|
||||
const N64Recomp::JumpTable& cur_jtbl = *find_result;
|
||||
print_line("gpr jr_addend_{:08X} = {}{}", cur_jtbl.jr_vram, ctx_gpr_prefix(cur_jtbl.addend_reg), cur_jtbl.addend_reg);
|
||||
}
|
||||
}
|
||||
|
|
@ -479,12 +479,12 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::F
|
|||
print_unconditional_branch("return");
|
||||
} else {
|
||||
auto jtbl_find_result = std::find_if(stats.jump_tables.begin(), stats.jump_tables.end(),
|
||||
[instr_vram](const RecompPort::JumpTable& jtbl) {
|
||||
[instr_vram](const N64Recomp::JumpTable& jtbl) {
|
||||
return jtbl.jr_vram == instr_vram;
|
||||
});
|
||||
|
||||
if (jtbl_find_result != stats.jump_tables.end()) {
|
||||
const RecompPort::JumpTable& cur_jtbl = *jtbl_find_result;
|
||||
const N64Recomp::JumpTable& cur_jtbl = *jtbl_find_result;
|
||||
bool dummy_needs_link_branch, dummy_is_branch_likely;
|
||||
size_t next_reloc_index = reloc_index;
|
||||
uint32_t next_vram = instr_vram + 4;
|
||||
|
|
@ -508,7 +508,7 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::F
|
|||
}
|
||||
|
||||
auto jump_find_result = std::find_if(stats.absolute_jumps.begin(), stats.absolute_jumps.end(),
|
||||
[instr_vram](const RecompPort::AbsoluteJump& jump) {
|
||||
[instr_vram](const N64Recomp::AbsoluteJump& jump) {
|
||||
return jump.instruction_vram == instr_vram;
|
||||
});
|
||||
|
||||
|
|
@ -718,7 +718,7 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::F
|
|||
return true;
|
||||
}
|
||||
|
||||
bool RecompPort::recompile_function(const RecompPort::Context& context, const RecompPort::Function& func, const std::string& recomp_include, std::ofstream& output_file, std::span<std::vector<uint32_t>> static_funcs_out, bool write_header) {
|
||||
bool N64Recomp::recompile_function(const N64Recomp::Context& context, const N64Recomp::Function& func, const std::string& recomp_include, std::ofstream& output_file, std::span<std::vector<uint32_t>> static_funcs_out, bool write_header) {
|
||||
//fmt::print("Recompiling {}\n", func.name);
|
||||
std::vector<rabbitizer::InstructionCpu> instructions;
|
||||
|
||||
|
|
@ -764,8 +764,8 @@ bool RecompPort::recompile_function(const RecompPort::Context& context, const Re
|
|||
}
|
||||
|
||||
// Analyze function
|
||||
RecompPort::FunctionStats stats{};
|
||||
if (!RecompPort::analyze_function(context, func, instructions, stats)) {
|
||||
N64Recomp::FunctionStats stats{};
|
||||
if (!N64Recomp::analyze_function(context, func, instructions, stats)) {
|
||||
fmt::print(stderr, "Failed to analyze {}\n", func.name);
|
||||
output_file.clear();
|
||||
return false;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue