Changed recomp port naming to N64Recomp

This commit is contained in:
Mr-Wiseguy 2024-07-08 16:54:35 -04:00
parent 9b0a349a5e
commit ff5797a2aa
11 changed files with 177 additions and 178 deletions

View file

@ -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;

View file

@ -21,7 +21,7 @@ constexpr uint32_t byteswap(uint32_t val) {
}
#endif
namespace RecompPort {
namespace N64Recomp {
struct Function {
uint32_t vram;
uint32_t rom;

View file

@ -5,7 +5,7 @@
#include "rabbitizer.hpp"
namespace RecompPort {
namespace N64Recomp {
using InstrId = rabbitizer::InstrId::UniqueId;
using Cop0Reg = rabbitizer::Registers::Cpu::Cop0;

View file

@ -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{};

View file

@ -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;

View file

@ -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{};

View file

@ -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());
}

View file

@ -5,7 +5,7 @@
#include <filesystem>
#include <vector>
namespace RecompPort {
namespace N64Recomp {
struct InstructionPatch {
std::string func_name;
int32_t vram;

View file

@ -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(&section);
}
);
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) {

View 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 } },

View file

@ -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;