Migrate to N64ModernRuntime (#354)

This commit is contained in:
David Chavez
2024-06-05 01:12:43 +02:00
committed by GitHub
parent 6e9ee3498b
commit bec699f0bd
72 changed files with 513 additions and 9741 deletions
+9
View File
@@ -0,0 +1,9 @@
#ifndef __OVL_PATCHES_HPP__
#define __OVL_PATCHES_HPP__
namespace zelda64 {
void register_overlays();
void register_patches();
}
#endif
-327
View File
@@ -1,327 +0,0 @@
#ifndef __RECOMP_H__
#define __RECOMP_H__
#include <stdint.h>
#include <math.h>
#include <assert.h>
#include <setjmp.h>
#include <malloc.h>
#if 0 // treat GPRs as 32-bit, should be better codegen
typedef uint32_t gpr;
#define SIGNED(val) \
((int32_t)(val))
#else
typedef uint64_t gpr;
#define SIGNED(val) \
((int64_t)(val))
#endif
#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)))
//(*(int32_t*)(rdram + ((((reg) + (offset))) & 0x3FFFFFF)))
#define MEM_H(offset, reg) \
(*(int16_t*)(rdram + ((((reg) + (offset)) ^ 2) - 0xFFFFFFFF80000000)))
//(*(int16_t*)(rdram + ((((reg) + (offset)) ^ 2) & 0x3FFFFFF)))
#define MEM_B(offset, reg) \
(*(int8_t*)(rdram + ((((reg) + (offset)) ^ 3) - 0xFFFFFFFF80000000)))
//(*(int8_t*)(rdram + ((((reg) + (offset)) ^ 3) & 0x3FFFFFF)))
#define MEM_HU(offset, reg) \
(*(uint16_t*)(rdram + ((((reg) + (offset)) ^ 2) - 0xFFFFFFFF80000000)))
//(*(uint16_t*)(rdram + ((((reg) + (offset)) ^ 2) & 0x3FFFFFF)))
#define MEM_BU(offset, reg) \
(*(uint8_t*)(rdram + ((((reg) + (offset)) ^ 3) - 0xFFFFFFFF80000000)))
//(*(uint8_t*)(rdram + ((((reg) + (offset)) ^ 3) & 0x3FFFFFF)))
#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); \
}
//#define SD(val, offset, reg) { \
// *(uint32_t*)(rdram + ((((reg) + (offset) + 4)) & 0x3FFFFFF)) = (uint32_t)((val) >> 32); \
// *(uint32_t*)(rdram + ((((reg) + (offset) + 0)) & 0x3FFFFFF)) = (uint32_t)((val) >> 0); \
//}
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))
// For Banjo-Tooie
void recomp_syscall_handler(uint8_t* rdram, recomp_context* ctx, int32_t instruction_vram);
// For the Mario Party games (not working)
//// This has to be in this file so it can be inlined
//struct jmp_buf_storage {
// jmp_buf buffer;
//};
//
//struct RecompJmpBuf {
// int32_t owner;
// struct jmp_buf_storage* storage;
// uint64_t magic;
//};
//
//// Randomly generated constant
//#define SETJMP_MAGIC 0xe17afdfa939a437bu
//
//int32_t osGetThreadEx(void);
//
//#define setjmp_recomp(rdram, ctx) { \
// struct RecompJmpBuf* buf = (struct RecompJmpBuf*)(&rdram[(uint64_t)ctx->r4 - 0xFFFFFFFF80000000]); \
// \
// /* Check if this jump buffer was previously set up */ \
// if (buf->magic == SETJMP_MAGIC) { \
// /* If so, free the old jmp_buf */ \
// free(buf->storage); \
// } \
// \
// buf->magic = SETJMP_MAGIC; \
// buf->owner = osGetThreadEx(); \
// buf->storage = (struct jmp_buf_storage*)calloc(1, sizeof(struct jmp_buf_storage)); \
// ctx->r2 = setjmp(buf->storage->buffer); \
//}
void pause_self(uint8_t *rdram);
#ifdef __cplusplus
}
#endif
#endif
-54
View File
@@ -1,54 +0,0 @@
#ifndef __RECOMP_CONFIG_H__
#define __RECOMP_CONFIG_H__
#include <filesystem>
#include <string_view>
#include "../ultramodern/config.hpp"
namespace recomp {
constexpr std::u8string_view program_id = u8"Zelda64Recompiled";
constexpr std::u8string_view mm_game_id = u8"mm.n64.us.1.0";
constexpr std::string_view program_name = "Zelda 64: Recompiled";
void load_config();
void save_config();
void reset_input_bindings();
void reset_cont_input_bindings();
void reset_kb_input_bindings();
std::filesystem::path get_app_folder_path();
bool get_debug_mode_enabled();
void set_debug_mode_enabled(bool enabled);
enum class AutosaveMode {
On,
Off,
OptionCount
};
enum class AnalogCamMode {
On,
Off,
OptionCount
};
NLOHMANN_JSON_SERIALIZE_ENUM(recomp::AutosaveMode, {
{recomp::AutosaveMode::On, "On"},
{recomp::AutosaveMode::Off, "Off"}
});
NLOHMANN_JSON_SERIALIZE_ENUM(recomp::AnalogCamMode, {
{recomp::AnalogCamMode::On, "On"},
{recomp::AnalogCamMode::Off, "Off"}
});
AutosaveMode get_autosave_mode();
void set_autosave_mode(AutosaveMode mode);
AnalogCamMode get_analog_cam_mode();
void set_analog_cam_mode(AnalogCamMode mode);
};
#endif
-40
View File
@@ -1,40 +0,0 @@
#ifndef __RECOMP_GAME__
#define __RECOMP_GAME__
#include <vector>
#include <filesystem>
#include "recomp.h"
#include "../ultramodern/ultramodern.hpp"
#include "rt64_layer.h"
namespace recomp {
enum class Game {
OoT,
MM,
None,
Quit
};
enum class RomValidationError {
Good,
FailedToOpen,
NotARom,
IncorrectRom,
NotYet,
IncorrectVersion,
OtherError
};
void check_all_stored_roms();
bool load_stored_rom(Game game);
RomValidationError select_rom(const std::filesystem::path& rom_path, Game game);
bool is_rom_valid(Game game);
bool is_rom_loaded();
void set_rom_contents(std::vector<uint8_t>&& new_rom);
void do_rom_read(uint8_t* rdram, gpr ram_address, uint32_t physical_addr, size_t num_bytes);
void do_rom_pio(uint8_t* rdram, gpr ram_address, uint32_t physical_addr);
void start(ultramodern::WindowHandle window_handle, const ultramodern::audio_callbacks_t& audio_callbacks, const ultramodern::input_callbacks_t& input_callbacks, const ultramodern::gfx_callbacks_t& gfx_callbacks);
void start_game(Game game);
void message_box(const char* message);
}
#endif
-50
View File
@@ -1,50 +0,0 @@
#ifndef __RECOMP_HELPERS__
#define __RECOMP_HELPERS__
#include "recomp.h"
#include "../ultramodern/ultra64.h"
template<int index, typename T>
T _arg(uint8_t* rdram, recomp_context* ctx) {
static_assert(index < 4, "Only args 0 through 3 supported");
gpr raw_arg = (&ctx->r4)[index];
if constexpr (std::is_same_v<T, float>) {
if constexpr (index < 2) {
static_assert(index != 1, "Floats in arg 1 not supported");
return ctx->f12.fl;
}
else {
// static_assert in else workaround
[] <bool flag = false>() {
static_assert(flag, "Floats in a2/a3 not supported");
}();
}
}
else if constexpr (std::is_pointer_v<T>) {
static_assert (!std::is_pointer_v<std::remove_pointer_t<T>>, "Double pointers not supported");
return TO_PTR(std::remove_pointer_t<T>, raw_arg);
}
else if constexpr (std::is_integral_v<T>) {
static_assert(sizeof(T) <= 4, "64-bit args not supported");
return static_cast<T>(raw_arg);
}
else {
// static_assert in else workaround
[] <bool flag = false>() {
static_assert(flag, "Unsupported type");
}();
}
}
template <typename T>
void _return(recomp_context* ctx, T val) {
static_assert(sizeof(T) <= 4 && "Only 32-bit value returns supported currently");
if (std::is_same_v<T, float>) {
ctx->f0.fl = val;
}
else if (std::is_integral_v<T> && sizeof(T) <= 4) {
ctx->r2 = int32_t(val);
}
}
#endif
+1 -41
View File
@@ -14,6 +14,7 @@
namespace recomp {
// x-macros to build input enums and arrays.
// First parameter is the enum name, second parameter is the bit field for the input (or 0 if there is no associated one), third is the readable name.
// TODO refactor this to allow projects to rename these, or get rid of the readable name and leave that up to individual projects to map.
#define DEFINE_N64_BUTTON_INPUTS() \
DEFINE_INPUT(A, 0x8000, "Action") \
DEFINE_INPUT(B, 0x4000, "Attack/Cancel") \
@@ -168,20 +169,6 @@ namespace recomp {
void apply_joystick_deadzone(float x_in, float y_in, float* x_out, float* y_out);
void set_right_analog_suppressed(bool suppressed);
enum class TargetingMode {
Switch,
Hold,
OptionCount
};
NLOHMANN_JSON_SERIALIZE_ENUM(recomp::TargetingMode, {
{recomp::TargetingMode::Switch, "Switch"},
{recomp::TargetingMode::Hold, "Hold"}
});
TargetingMode get_targeting_mode();
void set_targeting_mode(TargetingMode mode);
enum class BackgroundInputMode {
On,
Off,
@@ -196,35 +183,8 @@ namespace recomp {
BackgroundInputMode get_background_input_mode();
void set_background_input_mode(BackgroundInputMode mode);
enum class CameraInvertMode {
InvertNone,
InvertX,
InvertY,
InvertBoth,
OptionCount
};
NLOHMANN_JSON_SERIALIZE_ENUM(recomp::CameraInvertMode, {
{recomp::CameraInvertMode::InvertNone, "InvertNone"},
{recomp::CameraInvertMode::InvertX, "InvertX"},
{recomp::CameraInvertMode::InvertY, "InvertY"},
{recomp::CameraInvertMode::InvertBoth, "InvertBoth"}
});
CameraInvertMode get_camera_invert_mode();
void set_camera_invert_mode(CameraInvertMode mode);
CameraInvertMode get_analog_camera_invert_mode();
void set_analog_camera_invert_mode(CameraInvertMode mode);
bool game_input_disabled();
bool all_input_disabled();
// TODO move these
void quicksave_save();
void quicksave_load();
void open_quit_game_prompt();
}
#endif
-10
View File
@@ -1,10 +0,0 @@
#ifndef __RECOMP_OVERLAYS_H__
#define __RECOMP_OVERLAYS_H__
#include <cstdint>
extern "C" void load_overlays(uint32_t rom, int32_t ram_addr, uint32_t size);
extern "C" void unload_overlays(int32_t ram_addr, uint32_t size);
void init_overlays();
#endif
+3 -1
View File
@@ -14,7 +14,7 @@ namespace Rml {
class Event;
}
namespace recomp {
namespace recompui {
class UiEventListenerInstancer;
class MenuController {
@@ -118,6 +118,8 @@ namespace recomp {
bool get_cont_active(void);
void set_cont_active(bool active);
void activate_mouse();
void message_box(const char* msg);
}
#endif
-94
View File
@@ -1,94 +0,0 @@
#ifndef __RSP_H__
#define __RSP_H__
#include "rsp_vu.h"
#include "recomp.h"
#include <cstdio>
enum class RspExitReason {
Invalid,
Broke,
ImemOverrun,
UnhandledJumpTarget,
Unsupported
};
extern uint8_t dmem[];
extern uint16_t rspReciprocals[512];
extern uint16_t rspInverseSquareRoots[512];
#define RSP_MEM_B(offset, addr) \
(*reinterpret_cast<int8_t*>(dmem + (0xFFF & (((offset) + (addr)) ^ 3))))
#define RSP_MEM_BU(offset, addr) \
(*reinterpret_cast<uint8_t*>(dmem + (0xFFF & (((offset) + (addr)) ^ 3))))
static inline uint32_t RSP_MEM_W_LOAD(uint32_t offset, uint32_t addr) {
uint32_t out;
for (int i = 0; i < 4; i++) {
reinterpret_cast<uint8_t*>(&out)[i ^ 3] = RSP_MEM_BU(offset + i, addr);
}
return out;
}
static inline void RSP_MEM_W_STORE(uint32_t offset, uint32_t addr, uint32_t val) {
for (int i = 0; i < 4; i++) {
RSP_MEM_BU(offset + i, addr) = reinterpret_cast<uint8_t*>(&val)[i ^ 3];
}
}
static inline uint32_t RSP_MEM_HU_LOAD(uint32_t offset, uint32_t addr) {
uint16_t out;
for (int i = 0; i < 2; i++) {
reinterpret_cast<uint8_t*>(&out)[(i + 2) ^ 3] = RSP_MEM_BU(offset + i, addr);
}
return out;
}
static inline uint32_t RSP_MEM_H_LOAD(uint32_t offset, uint32_t addr) {
int16_t out;
for (int i = 0; i < 2; i++) {
reinterpret_cast<uint8_t*>(&out)[(i + 2) ^ 3] = RSP_MEM_BU(offset + i, addr);
}
return out;
}
static inline void RSP_MEM_H_STORE(uint32_t offset, uint32_t addr, uint32_t val) {
for (int i = 0; i < 2; i++) {
RSP_MEM_BU(offset + i, addr) = reinterpret_cast<uint8_t*>(&val)[(i + 2) ^ 3];
}
}
#define RSP_ADD32(a, b) \
((int32_t)((a) + (b)))
#define RSP_SUB32(a, b) \
((int32_t)((a) - (b)))
#define RSP_SIGNED(val) \
((int32_t)(val))
#define SET_DMA_DMEM(dmem_addr) dma_dmem_address = (dmem_addr)
#define SET_DMA_DRAM(dram_addr) dma_dram_address = (dram_addr)
#define DO_DMA_READ(rd_len) dma_rdram_to_dmem(rdram, dma_dmem_address, dma_dram_address, (rd_len))
#define DO_DMA_WRITE(wr_len) dma_dmem_to_rdram(rdram, dma_dmem_address, dma_dram_address, (wr_len))
static inline void dma_rdram_to_dmem(uint8_t* rdram, uint32_t dmem_addr, uint32_t dram_addr, uint32_t rd_len) {
rd_len += 1; // Read length is inclusive
dram_addr &= 0xFFFFF8;
assert(dmem_addr + rd_len <= 0x1000);
for (uint32_t i = 0; i < rd_len; i++) {
RSP_MEM_B(i, dmem_addr) = MEM_B(0, (int64_t)(int32_t)(dram_addr + i + 0x80000000));
}
}
static inline void dma_dmem_to_rdram(uint8_t* rdram, uint32_t dmem_addr, uint32_t dram_addr, uint32_t wr_len) {
wr_len += 1; // Write length is inclusive
dram_addr &= 0xFFFFF8;
assert(dmem_addr + wr_len <= 0x1000);
for (uint32_t i = 0; i < wr_len; i++) {
MEM_B(0, (int64_t)(int32_t)(dram_addr + i + 0x80000000)) = RSP_MEM_B(i, dmem_addr);
}
}
#endif
-203
View File
@@ -1,203 +0,0 @@
// This file is modified from the Ares N64 emulator core. Ares can
// be found at https://github.com/ares-emulator/ares. The original license
// for this portion of Ares is as follows:
// ----------------------------------------------------------------------
// ares
//
// Copyright(c) 2004 - 2021 ares team, Near et al
//
// Permission to use, copy, modify, and /or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright noticeand this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS.IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// ----------------------------------------------------------------------
#include <cstdint>
#if defined(__x86_64__) || defined(_M_X64)
#define ARCHITECTURE_SUPPORTS_SSE4_1 1
#include <nmmintrin.h>
using v128 = __m128i;
#elif defined(__aarch64__) || defined(_M_ARM64)
#define ARCHITECTURE_SUPPORTS_SSE4_1 1
#include "sse2neon.h"
using v128 = __m128i;
#endif
namespace Accuracy {
namespace RSP {
#if ARCHITECTURE_SUPPORTS_SSE4_1
constexpr bool SISD = false;
constexpr bool SIMD = true;
#else
constexpr bool SISD = true;
constexpr bool SIMD = false;
#endif
}
}
using u8 = uint8_t;
using s8 = int8_t;
using u16 = uint16_t;
using s16 = int16_t;
using u32 = uint32_t;
using s32 = int32_t;
using u64 = uint64_t;
using s64 = int64_t;
using uint128_t = uint64_t[2];
template<u32 bits> inline auto sclamp(s64 x) -> s64 {
enum : s64 { b = 1ull << (bits - 1), m = b - 1 };
return (x > m) ? m : (x < -b) ? -b : x;
}
template<u32 bits> inline auto sclip(s64 x) -> s64 {
enum : u64 { b = 1ull << (bits - 1), m = b * 2 - 1 };
return ((x & m) ^ b) - b;
}
struct RSP {
using r32 = uint32_t;
using cr32 = const r32;
union r128 {
struct { uint64_t u128[2]; };
#if ARCHITECTURE_SUPPORTS_SSE4_1
struct { __m128i v128; };
operator __m128i() const { return v128; }
auto operator=(__m128i value) { v128 = value; }
#endif
auto byte(u32 index) -> uint8_t& { return ((uint8_t*)&u128)[15 - index]; }
auto byte(u32 index) const -> uint8_t { return ((uint8_t*)&u128)[15 - index]; }
auto element(u32 index) -> uint16_t& { return ((uint16_t*)&u128)[7 - index]; }
auto element(u32 index) const -> uint16_t { return ((uint16_t*)&u128)[7 - index]; }
auto u8(u32 index) -> uint8_t& { return ((uint8_t*)&u128)[15 - index]; }
auto u8(u32 index) const -> uint8_t { return ((uint8_t*)&u128)[15 - index]; }
auto s16(u32 index) -> int16_t& { return ((int16_t*)&u128)[7 - index]; }
auto s16(u32 index) const -> int16_t { return ((int16_t*)&u128)[7 - index]; }
auto u16(u32 index) -> uint16_t& { return ((uint16_t*)&u128)[7 - index]; }
auto u16(u32 index) const -> uint16_t { return ((uint16_t*)&u128)[7 - index]; }
//VCx registers
auto get(u32 index) const -> bool { return u16(index) != 0; }
auto set(u32 index, bool value) -> bool { return u16(index) = 0 - value, value; }
//vu-registers.cpp
inline auto operator()(u32 index) const -> r128;
};
using cr128 = const r128;
struct VU {
r128 r[32];
r128 acch, accm, accl;
r128 vcoh, vcol; //16-bit little endian
r128 vcch, vccl; //16-bit little endian
r128 vce; // 8-bit little endian
s16 divin;
s16 divout;
bool divdp;
} vpu;
static constexpr r128 zero{0};
static constexpr r128 invert{(uint64_t)-1, (uint64_t)-1};
inline auto accumulatorGet(u32 index) const -> u64;
inline auto accumulatorSet(u32 index, u64 value) -> void;
inline auto accumulatorSaturate(u32 index, bool slice, u16 negative, u16 positive) const -> u16;
inline auto CFC2(r32& rt, u8 rd) -> void;
inline auto CTC2(cr32& rt, u8 rd) -> void;
template<u8 e> inline auto LBV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto LDV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto LFV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto LHV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto LLV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto LPV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto LQV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto LRV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto LSV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto LTV(u8 vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto LUV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto LWV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto MFC2(r32& rt, cr128& vs) -> void;
template<u8 e> inline auto MTC2(cr32& rt, r128& vs) -> void;
template<u8 e> inline auto SBV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto SDV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto SFV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto SHV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto SLV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto SPV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto SQV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto SRV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto SSV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto STV(u8 vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto SUV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto SWV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> inline auto VABS(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VADD(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VADDC(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VAND(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VCH(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VCL(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VCR(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VEQ(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VGE(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VLT(r128& vd, cr128& vs, cr128& vt) -> void;
template<bool U, u8 e>
inline auto VMACF(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VMACF(r128& vd, cr128& vs, cr128& vt) -> void { VMACF<0, e>(vd, vs, vt); }
template<u8 e> inline auto VMACU(r128& vd, cr128& vs, cr128& vt) -> void { VMACF<1, e>(vd, vs, vt); }
inline auto VMACQ(r128& vd) -> void;
template<u8 e> inline auto VMADH(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VMADL(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VMADM(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VMADN(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VMOV(r128& vd, u8 de, cr128& vt) -> void;
template<u8 e> inline auto VMRG(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VMUDH(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VMUDL(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VMUDM(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VMUDN(r128& vd, cr128& vs, cr128& vt) -> void;
template<bool U, u8 e>
inline auto VMULF(r128& rd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VMULF(r128& rd, cr128& vs, cr128& vt) -> void { VMULF<0, e>(rd, vs, vt); }
template<u8 e> inline auto VMULU(r128& rd, cr128& vs, cr128& vt) -> void { VMULF<1, e>(rd, vs, vt); }
template<u8 e> inline auto VMULQ(r128& rd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VNAND(r128& rd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VNE(r128& vd, cr128& vs, cr128& vt) -> void;
inline auto VNOP() -> void;
template<u8 e> inline auto VNOR(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VNXOR(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VOR(r128& vd, cr128& vs, cr128& vt) -> void;
template<bool L, u8 e>
inline auto VRCP(r128& vd, u8 de, cr128& vt) -> void;
template<u8 e> inline auto VRCP(r128& vd, u8 de, cr128& vt) -> void { VRCP<0, e>(vd, de, vt); }
template<u8 e> inline auto VRCPL(r128& vd, u8 de, cr128& vt) -> void { VRCP<1, e>(vd, de, vt); }
template<u8 e> inline auto VRCPH(r128& vd, u8 de, cr128& vt) -> void;
template<bool D, u8 e>
inline auto VRND(r128& vd, u8 vs, cr128& vt) -> void;
template<u8 e> inline auto VRNDN(r128& vd, u8 vs, cr128& vt) -> void { VRND<0, e>(vd, vs, vt); }
template<u8 e> inline auto VRNDP(r128& vd, u8 vs, cr128& vt) -> void { VRND<1, e>(vd, vs, vt); }
template<bool L, u8 e>
inline auto VRSQ(r128& vd, u8 de, cr128& vt) -> void;
template<u8 e> inline auto VRSQ(r128& vd, u8 de, cr128& vt) -> void { VRSQ<0, e>(vd, de, vt); }
template<u8 e> inline auto VRSQL(r128& vd, u8 de, cr128& vt) -> void { VRSQ<1, e>(vd, de, vt); }
template<u8 e> inline auto VRSQH(r128& vd, u8 de, cr128& vt) -> void;
template<u8 e> inline auto VSAR(r128& vd, cr128& vs) -> void;
template<u8 e> inline auto VSUB(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VSUBC(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VXOR(r128& rd, cr128& vs, cr128& vt) -> void;
template<u8 e> inline auto VZERO(r128& rd, cr128& vs, cr128& vt) -> void;
};
File diff suppressed because it is too large Load Diff
-50
View File
@@ -1,50 +0,0 @@
#ifndef __RT64_LAYER_H__
#define __RT64_LAYER_H__
#include "../ultramodern/ultramodern.hpp"
#include "../ultramodern/config.hpp"
namespace RT64 {
struct Application;
}
namespace ultramodern {
enum class RT64SetupResult {
Success,
DynamicLibrariesNotFound,
InvalidGraphicsAPI,
GraphicsAPINotFound,
GraphicsDeviceNotFound
};
struct WindowHandle;
struct RT64Context {
public:
~RT64Context();
RT64Context(uint8_t* rdram, WindowHandle window_handle, bool developer_mode);
bool valid() { return static_cast<bool>(app); }
RT64SetupResult get_setup_result() { return setup_result; }
void update_config(const GraphicsConfig& old_config, const GraphicsConfig& new_config);
void enable_instant_present();
void send_dl(const OSTask* task);
void update_screen(uint32_t vi_origin);
void shutdown();
void set_dummy_vi();
uint32_t get_display_framerate();
float get_resolution_scale();
void load_shader_cache(std::span<const char> cache_binary);
private:
RT64SetupResult setup_result;
std::unique_ptr<RT64::Application> app;
};
RT64::UserConfiguration::Antialiasing RT64MaxMSAA();
bool RT64SamplePositionsSupported();
bool RT64HighPrecisionFBEnabled();
}
void set_rt64_hooks();
#endif
-23
View File
@@ -1,23 +0,0 @@
#ifndef __SECTIONS_H__
#define __SECTIONS_H__
#include <stdint.h>
#include "recomp.h"
#define ARRLEN(x) (sizeof(x) / sizeof((x)[0]))
typedef struct {
recomp_func_t* func;
uint32_t offset;
} FuncEntry;
typedef struct {
uint32_t rom_addr;
uint32_t ram_addr;
uint32_t size;
FuncEntry *funcs;
size_t num_funcs;
size_t index;
} SectionTableEntry;
#endif
+91
View File
@@ -0,0 +1,91 @@
#ifndef __ZELDA_CONFIG_H__
#define __ZELDA_CONFIG_H__
#include <filesystem>
#include <string_view>
#include "ultramodern/config.hpp"
namespace zelda64 {
constexpr std::u8string_view program_id = u8"Zelda64Recompiled";
constexpr std::string_view program_name = "Zelda 64: Recompiled";
// TODO: Move loading configs to the runtime once we have a way to allow per-project customization.
void load_config();
void save_config();
void reset_input_bindings();
void reset_cont_input_bindings();
void reset_kb_input_bindings();
std::filesystem::path get_app_folder_path();
bool get_debug_mode_enabled();
void set_debug_mode_enabled(bool enabled);
enum class AutosaveMode {
On,
Off,
OptionCount
};
NLOHMANN_JSON_SERIALIZE_ENUM(zelda64::AutosaveMode, {
{zelda64::AutosaveMode::On, "On"},
{zelda64::AutosaveMode::Off, "Off"}
});
enum class TargetingMode {
Switch,
Hold,
OptionCount
};
NLOHMANN_JSON_SERIALIZE_ENUM(zelda64::TargetingMode, {
{zelda64::TargetingMode::Switch, "Switch"},
{zelda64::TargetingMode::Hold, "Hold"}
});
TargetingMode get_targeting_mode();
void set_targeting_mode(TargetingMode mode);
enum class CameraInvertMode {
InvertNone,
InvertX,
InvertY,
InvertBoth,
OptionCount
};
NLOHMANN_JSON_SERIALIZE_ENUM(zelda64::CameraInvertMode, {
{zelda64::CameraInvertMode::InvertNone, "InvertNone"},
{zelda64::CameraInvertMode::InvertX, "InvertX"},
{zelda64::CameraInvertMode::InvertY, "InvertY"},
{zelda64::CameraInvertMode::InvertBoth, "InvertBoth"}
});
CameraInvertMode get_camera_invert_mode();
void set_camera_invert_mode(CameraInvertMode mode);
CameraInvertMode get_analog_camera_invert_mode();
void set_analog_camera_invert_mode(CameraInvertMode mode);
enum class AnalogCamMode {
On,
Off,
OptionCount
};
NLOHMANN_JSON_SERIALIZE_ENUM(zelda64::AnalogCamMode, {
{zelda64::AnalogCamMode::On, "On"},
{zelda64::AnalogCamMode::Off, "Off"}
});
AutosaveMode get_autosave_mode();
void set_autosave_mode(AutosaveMode mode);
AnalogCamMode get_analog_cam_mode();
void set_analog_cam_mode(AnalogCamMode mode);
void open_quit_game_prompt();
};
#endif
@@ -1,10 +1,10 @@
#ifndef __RECOMP_DEBUG_H__
#define __RECOMP_DEBUG_H__
#ifndef __ZELDA_DEBUG_H__
#define __ZELDA_DEBUG_H__
#include <vector>
#include <string>
namespace recomp {
namespace zelda64 {
struct SceneWarps {
int index;
std::string name;
+9
View File
@@ -0,0 +1,9 @@
#ifndef __ZELDA_GAME_H__
#define __ZELDA_GAME_H__
namespace zelda64 {
void quicksave_save();
void quicksave_load();
};
#endif
@@ -1,7 +1,7 @@
#ifndef __RECOMP_SOUND_H__
#define __RECOMP_SOUND_H__
#ifndef __ZELDA_SOUND_H__
#define __ZELDA_SOUND_H__
namespace recomp {
namespace zelda64 {
void reset_sound_settings();
void set_main_volume(int volume);
int get_main_volume();