mirror of
https://github.com/N64Recomp/N64Recomp.git
synced 2025-05-14 08:12:19 +00:00
Reorganized headers and add recomp.h from modern runtime
This commit is contained in:
parent
adaca23f09
commit
1aa4ad6518
17 changed files with 308 additions and 21 deletions
|
@ -159,14 +159,8 @@ project(OfflineModRecomp)
|
||||||
add_executable(OfflineModRecomp)
|
add_executable(OfflineModRecomp)
|
||||||
|
|
||||||
target_sources(OfflineModRecomp PRIVATE
|
target_sources(OfflineModRecomp PRIVATE
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/../sljit/sljit_src/sljitLir.c
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/config.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/config.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/OfflineModRecomp/main.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/OfflineModRecomp/main.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/OfflineModRecomp/sljit_generator.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
target_include_directories(OfflineModRecomp PRIVATE
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/../sljit/sljit_src
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(OfflineModRecomp fmt rabbitizer tomlplusplus::tomlplusplus N64Recomp)
|
target_link_libraries(OfflineModRecomp fmt rabbitizer tomlplusplus::tomlplusplus N64Recomp)
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <span>
|
#include <span>
|
||||||
|
|
||||||
#include "n64recomp.h"
|
#include "recompiler/context.h"
|
||||||
#include "rabbitizer.hpp"
|
#include "rabbitizer.hpp"
|
||||||
|
|
||||||
static std::vector<uint8_t> read_file(const std::filesystem::path& path, bool& found) {
|
static std::vector<uint8_t> read_file(const std::filesystem::path& path, bool& found) {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "fmt/ostream.h"
|
#include "fmt/ostream.h"
|
||||||
#include "n64recomp.h"
|
#include "recompiler/context.h"
|
||||||
#include <toml++/toml.hpp>
|
#include <toml++/toml.hpp>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
293
include/recomp.h
Normal file
293
include/recomp.h
Normal file
|
@ -0,0 +1,293 @@
|
||||||
|
#ifndef __RECOMP_H__
|
||||||
|
#define __RECOMP_H__
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
// Compiler definition to disable inter-procedural optimization, allowing multiple functions to be in a single file without breaking interposition.
|
||||||
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
// MSVC's __declspec(noinline) seems to disable inter-procedural optimization entirely, so it's all that's needed.
|
||||||
|
#define RECOMP_FUNC __declspec(noinline)
|
||||||
|
#elif defined(__clang__)
|
||||||
|
// Clang has no dedicated IPO attribute, so we use a combination of other attributes to give the desired behavior.
|
||||||
|
// The inline keyword allows multiple definitions during linking, and extern forces clang to emit an externally visible definition.
|
||||||
|
// Weak forces Clang to not perform any IPO as the symbol can be interposed, which prevents actual inlining due to the inline keyword.
|
||||||
|
// Add noinline on for good measure, which doesn't conflict with the inline keyword as they have different meanings.
|
||||||
|
#define RECOMP_FUNC extern inline __attribute__((weak,noinline))
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
// Use GCC's attribute for disabling inter-procedural optimizations.
|
||||||
|
#define RECOMP_FUNC __attribute__((noipa))
|
||||||
|
#else
|
||||||
|
#error "No RECOMP_FUNC definition for this compiler"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef uint64_t gpr;
|
||||||
|
|
||||||
|
#define SIGNED(val) \
|
||||||
|
((int64_t)(val))
|
||||||
|
|
||||||
|
#define ADD32(a, b) \
|
||||||
|
((gpr)(int32_t)((a) + (b)))
|
||||||
|
|
||||||
|
#define SUB32(a, b) \
|
||||||
|
((gpr)(int32_t)((a) - (b)))
|
||||||
|
|
||||||
|
#define MEM_W(offset, reg) \
|
||||||
|
(*(int32_t*)(rdram + ((((reg) + (offset))) - 0xFFFFFFFF80000000)))
|
||||||
|
|
||||||
|
#define MEM_H(offset, reg) \
|
||||||
|
(*(int16_t*)(rdram + ((((reg) + (offset)) ^ 2) - 0xFFFFFFFF80000000)))
|
||||||
|
|
||||||
|
#define MEM_B(offset, reg) \
|
||||||
|
(*(int8_t*)(rdram + ((((reg) + (offset)) ^ 3) - 0xFFFFFFFF80000000)))
|
||||||
|
|
||||||
|
#define MEM_HU(offset, reg) \
|
||||||
|
(*(uint16_t*)(rdram + ((((reg) + (offset)) ^ 2) - 0xFFFFFFFF80000000)))
|
||||||
|
|
||||||
|
#define MEM_BU(offset, reg) \
|
||||||
|
(*(uint8_t*)(rdram + ((((reg) + (offset)) ^ 3) - 0xFFFFFFFF80000000)))
|
||||||
|
|
||||||
|
#define SD(val, offset, reg) { \
|
||||||
|
*(uint32_t*)(rdram + ((((reg) + (offset) + 4)) - 0xFFFFFFFF80000000)) = (uint32_t)((gpr)(val) >> 0); \
|
||||||
|
*(uint32_t*)(rdram + ((((reg) + (offset) + 0)) - 0xFFFFFFFF80000000)) = (uint32_t)((gpr)(val) >> 32); \
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t load_doubleword(uint8_t* rdram, gpr reg, gpr offset) {
|
||||||
|
uint64_t ret = 0;
|
||||||
|
uint64_t lo = (uint64_t)(uint32_t)MEM_W(reg, offset + 4);
|
||||||
|
uint64_t hi = (uint64_t)(uint32_t)MEM_W(reg, offset + 0);
|
||||||
|
ret = (lo << 0) | (hi << 32);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LD(offset, reg) \
|
||||||
|
load_doubleword(rdram, offset, reg)
|
||||||
|
|
||||||
|
static inline gpr do_lwl(uint8_t* rdram, gpr initial_value, gpr offset, gpr reg) {
|
||||||
|
// Calculate the overall address
|
||||||
|
gpr address = (offset + reg);
|
||||||
|
|
||||||
|
// Load the aligned word
|
||||||
|
gpr word_address = address & ~0x3;
|
||||||
|
uint32_t loaded_value = MEM_W(0, word_address);
|
||||||
|
|
||||||
|
// Mask the existing value and shift the loaded value appropriately
|
||||||
|
gpr misalignment = address & 0x3;
|
||||||
|
gpr masked_value = initial_value & ~(0xFFFFFFFFu << (misalignment * 8));
|
||||||
|
loaded_value <<= (misalignment * 8);
|
||||||
|
|
||||||
|
// Cast to int32_t to sign extend first
|
||||||
|
return (gpr)(int32_t)(masked_value | loaded_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline gpr do_lwr(uint8_t* rdram, gpr initial_value, gpr offset, gpr reg) {
|
||||||
|
// Calculate the overall address
|
||||||
|
gpr address = (offset + reg);
|
||||||
|
|
||||||
|
// Load the aligned word
|
||||||
|
gpr word_address = address & ~0x3;
|
||||||
|
uint32_t loaded_value = MEM_W(0, word_address);
|
||||||
|
|
||||||
|
// Mask the existing value and shift the loaded value appropriately
|
||||||
|
gpr misalignment = address & 0x3;
|
||||||
|
gpr masked_value = initial_value & ~(0xFFFFFFFFu >> (24 - misalignment * 8));
|
||||||
|
loaded_value >>= (24 - misalignment * 8);
|
||||||
|
|
||||||
|
// Cast to int32_t to sign extend first
|
||||||
|
return (gpr)(int32_t)(masked_value | loaded_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void do_swl(uint8_t* rdram, gpr offset, gpr reg, gpr val) {
|
||||||
|
// Calculate the overall address
|
||||||
|
gpr address = (offset + reg);
|
||||||
|
|
||||||
|
// Get the initial value of the aligned word
|
||||||
|
gpr word_address = address & ~0x3;
|
||||||
|
uint32_t initial_value = MEM_W(0, word_address);
|
||||||
|
|
||||||
|
// Mask the initial value and shift the input value appropriately
|
||||||
|
gpr misalignment = address & 0x3;
|
||||||
|
uint32_t masked_initial_value = initial_value & ~(0xFFFFFFFFu >> (misalignment * 8));
|
||||||
|
uint32_t shifted_input_value = ((uint32_t)val) >> (misalignment * 8);
|
||||||
|
MEM_W(0, word_address) = masked_initial_value | shifted_input_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void do_swr(uint8_t* rdram, gpr offset, gpr reg, gpr val) {
|
||||||
|
// Calculate the overall address
|
||||||
|
gpr address = (offset + reg);
|
||||||
|
|
||||||
|
// Get the initial value of the aligned word
|
||||||
|
gpr word_address = address & ~0x3;
|
||||||
|
uint32_t initial_value = MEM_W(0, word_address);
|
||||||
|
|
||||||
|
// Mask the initial value and shift the input value appropriately
|
||||||
|
gpr misalignment = address & 0x3;
|
||||||
|
uint32_t masked_initial_value = initial_value & ~(0xFFFFFFFFu << (24 - misalignment * 8));
|
||||||
|
uint32_t shifted_input_value = ((uint32_t)val) << (24 - misalignment * 8);
|
||||||
|
MEM_W(0, word_address) = masked_initial_value | shifted_input_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define S32(val) \
|
||||||
|
((int32_t)(val))
|
||||||
|
|
||||||
|
#define U32(val) \
|
||||||
|
((uint32_t)(val))
|
||||||
|
|
||||||
|
#define S64(val) \
|
||||||
|
((int64_t)(val))
|
||||||
|
|
||||||
|
#define U64(val) \
|
||||||
|
((uint64_t)(val))
|
||||||
|
|
||||||
|
#define MUL_S(val1, val2) \
|
||||||
|
((val1) * (val2))
|
||||||
|
|
||||||
|
#define MUL_D(val1, val2) \
|
||||||
|
((val1) * (val2))
|
||||||
|
|
||||||
|
#define DIV_S(val1, val2) \
|
||||||
|
((val1) / (val2))
|
||||||
|
|
||||||
|
#define DIV_D(val1, val2) \
|
||||||
|
((val1) / (val2))
|
||||||
|
|
||||||
|
#define CVT_S_W(val) \
|
||||||
|
((float)((int32_t)(val)))
|
||||||
|
|
||||||
|
#define CVT_D_W(val) \
|
||||||
|
((double)((int32_t)(val)))
|
||||||
|
|
||||||
|
#define CVT_D_S(val) \
|
||||||
|
((double)(val))
|
||||||
|
|
||||||
|
#define CVT_S_D(val) \
|
||||||
|
((float)(val))
|
||||||
|
|
||||||
|
#define TRUNC_W_S(val) \
|
||||||
|
((int32_t)(val))
|
||||||
|
|
||||||
|
#define TRUNC_W_D(val) \
|
||||||
|
((int32_t)(val))
|
||||||
|
|
||||||
|
#define TRUNC_L_S(val) \
|
||||||
|
((int64_t)(val))
|
||||||
|
|
||||||
|
#define TRUNC_L_D(val) \
|
||||||
|
((int64_t)(val))
|
||||||
|
|
||||||
|
#define DEFAULT_ROUNDING_MODE 0
|
||||||
|
|
||||||
|
static inline int32_t do_cvt_w_s(float val, unsigned int rounding_mode) {
|
||||||
|
switch (rounding_mode) {
|
||||||
|
case 0: // round to nearest value
|
||||||
|
return (int32_t)lroundf(val);
|
||||||
|
case 1: // round to zero (truncate)
|
||||||
|
return (int32_t)val;
|
||||||
|
case 2: // round to positive infinity (ceil)
|
||||||
|
return (int32_t)ceilf(val);
|
||||||
|
case 3: // round to negative infinity (floor)
|
||||||
|
return (int32_t)floorf(val);
|
||||||
|
}
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CVT_W_S(val) \
|
||||||
|
do_cvt_w_s(val, rounding_mode)
|
||||||
|
|
||||||
|
static inline int32_t do_cvt_w_d(double val, unsigned int rounding_mode) {
|
||||||
|
switch (rounding_mode) {
|
||||||
|
case 0: // round to nearest value
|
||||||
|
return (int32_t)lround(val);
|
||||||
|
case 1: // round to zero (truncate)
|
||||||
|
return (int32_t)val;
|
||||||
|
case 2: // round to positive infinity (ceil)
|
||||||
|
return (int32_t)ceil(val);
|
||||||
|
case 3: // round to negative infinity (floor)
|
||||||
|
return (int32_t)floor(val);
|
||||||
|
}
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CVT_W_D(val) \
|
||||||
|
do_cvt_w_d(val, rounding_mode)
|
||||||
|
|
||||||
|
#define NAN_CHECK(val) \
|
||||||
|
assert(val == val)
|
||||||
|
|
||||||
|
//#define NAN_CHECK(val)
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
double d;
|
||||||
|
struct {
|
||||||
|
float fl;
|
||||||
|
float fh;
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
uint32_t u32l;
|
||||||
|
uint32_t u32h;
|
||||||
|
};
|
||||||
|
uint64_t u64;
|
||||||
|
} fpr;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gpr r0, r1, r2, r3, r4, r5, r6, r7,
|
||||||
|
r8, r9, r10, r11, r12, r13, r14, r15,
|
||||||
|
r16, r17, r18, r19, r20, r21, r22, r23,
|
||||||
|
r24, r25, r26, r27, r28, r29, r30, r31;
|
||||||
|
fpr f0, f1, f2, f3, f4, f5, f6, f7,
|
||||||
|
f8, f9, f10, f11, f12, f13, f14, f15,
|
||||||
|
f16, f17, f18, f19, f20, f21, f22, f23,
|
||||||
|
f24, f25, f26, f27, f28, f29, f30, f31;
|
||||||
|
uint64_t hi, lo;
|
||||||
|
uint32_t* f_odd;
|
||||||
|
uint32_t status_reg;
|
||||||
|
uint8_t mips3_float_mode;
|
||||||
|
} recomp_context;
|
||||||
|
|
||||||
|
// Checks if the target is an even float register or that mips3 float mode is enabled
|
||||||
|
#define CHECK_FR(ctx, idx) \
|
||||||
|
assert(((idx) & 1) == 0 || (ctx)->mips3_float_mode)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void cop0_status_write(recomp_context* ctx, gpr value);
|
||||||
|
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);
|
||||||
|
|
||||||
|
typedef void (recomp_func_t)(uint8_t* rdram, recomp_context* ctx);
|
||||||
|
|
||||||
|
recomp_func_t* get_function(int32_t vram);
|
||||||
|
|
||||||
|
#define LOOKUP_FUNC(val) \
|
||||||
|
get_function((int32_t)(val))
|
||||||
|
|
||||||
|
extern int32_t* section_addresses;
|
||||||
|
|
||||||
|
#define LO16(x) \
|
||||||
|
((x) & 0xFFFF)
|
||||||
|
|
||||||
|
#define HI16(x) \
|
||||||
|
(((x) >> 16) + (((x) >> 15) & 1))
|
||||||
|
|
||||||
|
#define RELOC_HI16(section_index, offset) \
|
||||||
|
HI16(section_addresses[section_index] + (offset))
|
||||||
|
|
||||||
|
#define RELOC_LO16(section_index, offset) \
|
||||||
|
LO16(section_addresses[section_index] + (offset))
|
||||||
|
|
||||||
|
void recomp_syscall_handler(uint8_t* rdram, recomp_context* ctx, int32_t instruction_vram);
|
||||||
|
|
||||||
|
void pause_self(uint8_t *rdram);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef __GENERATOR_H__
|
#ifndef __GENERATOR_H__
|
||||||
#define __GENERATOR_H__
|
#define __GENERATOR_H__
|
||||||
|
|
||||||
#include "n64recomp.h"
|
#include "recompiler/context.h"
|
||||||
#include "operations.h"
|
#include "operations.h"
|
||||||
|
|
||||||
namespace N64Recomp {
|
namespace N64Recomp {
|
|
@ -4,7 +4,7 @@
|
||||||
#include "rabbitizer.hpp"
|
#include "rabbitizer.hpp"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
|
|
||||||
#include "n64recomp.h"
|
#include "recompiler/context.h"
|
||||||
#include "analysis.h"
|
#include "analysis.h"
|
||||||
|
|
||||||
extern "C" const char* RabbitizerRegister_getNameGpr(uint8_t regValue);
|
extern "C" const char* RabbitizerRegister_getNameGpr(uint8_t regValue);
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "n64recomp.h"
|
#include "recompiler/context.h"
|
||||||
|
|
||||||
namespace N64Recomp {
|
namespace N64Recomp {
|
||||||
struct JumpTable {
|
struct JumpTable {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "fmt/ostream.h"
|
#include "fmt/ostream.h"
|
||||||
|
|
||||||
#include "generator.h"
|
#include "recompiler/generator.h"
|
||||||
|
|
||||||
struct BinaryOpFields { std::string func_string; std::string infix_string; };
|
struct BinaryOpFields { std::string func_string; std::string infix_string; };
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include <toml++/toml.hpp>
|
#include <toml++/toml.hpp>
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "n64recomp.h"
|
#include "recompiler/context.h"
|
||||||
|
|
||||||
std::filesystem::path concat_if_not_empty(const std::filesystem::path& parent, const std::filesystem::path& child) {
|
std::filesystem::path concat_if_not_empty(const std::filesystem::path& parent, const std::filesystem::path& child) {
|
||||||
if (!child.empty()) {
|
if (!child.empty()) {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
// #include "fmt/ostream.h"
|
// #include "fmt/ostream.h"
|
||||||
|
|
||||||
#include "n64recomp.h"
|
#include "recompiler/context.h"
|
||||||
#include "elfio/elfio.hpp"
|
#include "elfio/elfio.hpp"
|
||||||
|
|
||||||
bool read_symbols(N64Recomp::Context& context, const ELFIO::elfio& elf_file, ELFIO::section* symtab_section, const N64Recomp::ElfParsingConfig& elf_config, bool dumping_context, std::unordered_map<uint16_t, std::vector<N64Recomp::DataSymbol>>& data_syms) {
|
bool read_symbols(N64Recomp::Context& context, const ELFIO::elfio& elf_file, ELFIO::section* symtab_section, const N64Recomp::ElfParsingConfig& elf_config, bool dumping_context, std::unordered_map<uint16_t, std::vector<N64Recomp::DataSymbol>>& data_syms) {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "fmt/ostream.h"
|
#include "fmt/ostream.h"
|
||||||
|
|
||||||
#include "n64recomp.h"
|
#include "recompiler/context.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "n64recomp.h"
|
#include "recompiler/context.h"
|
||||||
|
|
||||||
struct FileHeader {
|
struct FileHeader {
|
||||||
char magic[8]; // N64RSYMS
|
char magic[8]; // N64RSYMS
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "operations.h"
|
#include "recompiler/operations.h"
|
||||||
|
|
||||||
namespace N64Recomp {
|
namespace N64Recomp {
|
||||||
const std::unordered_map<InstrId, UnaryOp> unary_ops {
|
const std::unordered_map<InstrId, UnaryOp> unary_ops {
|
||||||
|
|
|
@ -8,10 +8,10 @@
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "fmt/ostream.h"
|
#include "fmt/ostream.h"
|
||||||
|
|
||||||
#include "n64recomp.h"
|
#include "recompiler/context.h"
|
||||||
#include "analysis.h"
|
#include "analysis.h"
|
||||||
#include "operations.h"
|
#include "recompiler/operations.h"
|
||||||
#include "generator.h"
|
#include "recompiler/generator.h"
|
||||||
|
|
||||||
enum class JalResolutionResult {
|
enum class JalResolutionResult {
|
||||||
NoMatch,
|
NoMatch,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "n64recomp.h"
|
#include "recompiler/context.h"
|
||||||
|
|
||||||
const std::unordered_set<std::string> N64Recomp::reimplemented_funcs {
|
const std::unordered_set<std::string> N64Recomp::reimplemented_funcs {
|
||||||
// OS initialize functions
|
// OS initialize functions
|
||||||
|
|
Loading…
Add table
Reference in a new issue