2 Commits

Author SHA1 Message Date
Wiseguy
be65d37760 Added config option parsing for mod toml and populate them in the mod manifest (#129) 2025-01-31 02:36:33 -05:00
Wiseguy
2af6f2d161 Implement shim function generation (#128) 2025-01-30 23:48:20 -05:00
4 changed files with 71 additions and 0 deletions

View File

@@ -1896,3 +1896,29 @@ bool N64Recomp::recompile_function_live(LiveGenerator& generator, const Context&
return recompile_function_custom(generator, context, function_index, output_file, static_funcs_out, tag_reference_relocs);
}
N64Recomp::ShimFunction::ShimFunction(recomp_func_ext_t* to_shim, uintptr_t value) {
sljit_compiler* compiler = sljit_create_compiler(nullptr);
// Create the function.
sljit_label* func_label = sljit_emit_label(compiler);
sljit_emit_enter(compiler, 0, SLJIT_ARGS2V(P_R, P_R), 3, 0, 0);
// Move the provided value into the third argument.
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, sljit_sw(value));
// Tail call the provided function.
sljit_emit_icall(compiler, SLJIT_CALL | SLJIT_CALL_RETURN, SLJIT_ARGS3V(P, P, W), SLJIT_IMM, sljit_sw(to_shim));
// Generate the function's code and get the address to the function.
code = sljit_generate_code(compiler, 0, nullptr);
func = reinterpret_cast<recomp_func_t*>(sljit_get_label_addr(func_label));
// Cleanup.
sljit_free_compiler(compiler);
}
N64Recomp::ShimFunction::~ShimFunction() {
sljit_free_code(code, nullptr);
code = nullptr;
func = nullptr;
}

View File

@@ -32,6 +32,7 @@ struct ModManifest {
std::string game_id;
std::string minimum_recomp_version;
std::unordered_map<std::string, std::vector<std::string>> native_libraries;
std::vector<toml::table> config_options;
std::vector<std::string> dependencies;
std::vector<std::string> full_dependency_strings;
};
@@ -218,6 +219,11 @@ static std::vector<std::filesystem::path> get_toml_path_array(const toml::array&
return ret;
}
bool validate_config_option(const toml::table& option) {
// TODO config option validation.
return true;
}
ModManifest parse_mod_config_manifest(const std::filesystem::path& basedir, const toml::table& manifest_table) {
ModManifest ret;
@@ -317,6 +323,23 @@ ModManifest parse_mod_config_manifest(const std::filesystem::path& basedir, cons
});
}
// Config schema (optional)
const toml::array& config_options_array = read_toml_array(manifest_table, "config_options", false);
if (!config_options_array.empty()) {
ret.config_options.reserve(config_options_array.size());
config_options_array.for_each([&ret](const auto& el) {
if constexpr (toml::is_table<decltype(el)>) {
if (!validate_config_option(el)) {
throw toml::parse_error("Invalid config option", el.source());
}
ret.config_options.emplace_back(el);
}
else {
throw toml::parse_error("Invalid type for config option", el.source());
}
});
}
return ret;
}
@@ -484,6 +507,14 @@ void write_manifest(const std::filesystem::path& path, const ModManifest& manife
output_data.emplace("dependencies", string_vector_to_toml(manifest.full_dependency_strings));
}
if (!manifest.config_options.empty()) {
toml::array options_array{};
for (const auto& option : manifest.config_options) {
options_array.emplace_back(option);
}
output_data.emplace("config_schema", toml::table{{"options", std::move(options_array)}});
}
toml::json_formatter formatter{output_data, toml::format_flags::indentation | toml::format_flags::indentation};
std::ofstream output_file(path);

View File

@@ -439,7 +439,11 @@ gpr cop0_status_read(recomp_context* ctx);
void switch_error(const char* func, uint32_t vram, uint32_t jtbl);
void do_break(uint32_t vram);
// The function signature for all recompiler output functions.
typedef void (recomp_func_t)(uint8_t* rdram, recomp_context* ctx);
// The function signature for special functions that need a third argument.
// These get called via generated shims to allow providing some information about the caller, such as mod id.
typedef void (recomp_func_ext_t)(uint8_t* rdram, recomp_context* ctx, uintptr_t arg);
recomp_func_t* get_function(int32_t vram);

View File

@@ -141,6 +141,16 @@ namespace N64Recomp {
void live_recompiler_init();
bool recompile_function_live(LiveGenerator& generator, const Context& context, size_t function_index, std::ostream& output_file, std::span<std::vector<uint32_t>> static_funcs_out, bool tag_reference_relocs);
class ShimFunction {
private:
void* code;
recomp_func_t* func;
public:
ShimFunction(recomp_func_ext_t* to_shim, uintptr_t value);
~ShimFunction();
recomp_func_t* get_func() { return func; }
};
}
#endif