format librecomp

This commit is contained in:
angie 2024-06-10 10:34:45 -04:00
parent 108a240186
commit 0bec4adafc
23 changed files with 389 additions and 372 deletions

View file

@ -9,6 +9,6 @@ namespace recomp {
std::ifstream open_input_backup_file(const std::filesystem::path& filepath, std::ios_base::openmode mode = std::ios_base::in);
std::ofstream open_output_file_with_backup(const std::filesystem::path& filepath, std::ios_base::openmode mode = std::ios_base::out);
bool finalize_output_file_with_backup(const std::filesystem::path& filepath);
};
}; // namespace recomp
#endif

View file

@ -1,8 +1,8 @@
#ifndef __RECOMP_GAME__
#define __RECOMP_GAME__
#include <vector>
#include <filesystem>
#include <vector>
#include "recomp.h"
#include "rsp.hpp"
@ -17,50 +17,46 @@ namespace recomp {
bool is_enabled;
gpr entrypoint_address;
void (*entrypoint)(uint8_t* rdram, recomp_context* context);
void (*entrypoint)(uint8_t *rdram, recomp_context *context);
std::u8string stored_filename() const;
};
enum class RomValidationError {
Good,
FailedToOpen,
NotARom,
IncorrectRom,
NotYet,
IncorrectVersion,
OtherError
};
void register_config_path(std::filesystem::path path);
bool register_game(const recomp::GameEntry& entry);
void check_all_stored_roms();
bool load_stored_rom(std::u8string& game_id);
RomValidationError select_rom(const std::filesystem::path& rom_path, std::u8string& game_id);
bool is_rom_valid(std::u8string& game_id);
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);
enum class RomValidationError {
Good,
FailedToOpen,
NotARom,
IncorrectRom,
NotYet,
IncorrectVersion,
OtherError
};
void register_config_path(std::filesystem::path path);
bool register_game(const recomp::GameEntry& entry);
void check_all_stored_roms();
bool load_stored_rom(std::u8string& game_id);
RomValidationError select_rom(const std::filesystem::path& rom_path, std::u8string& game_id);
bool is_rom_valid(std::u8string& game_id);
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);
/**
* The following arguments contain mandatory callbacks that need to be registered (i.e., can't be `nullptr`):
* - `rsp_callbacks`
* - `renderer_callbacks`
*
* It must be called only once and it must be called before `ultramodern::preinit`.
*/
/**
* The following arguments contain mandatory callbacks that need to be registered (i.e., can't be `nullptr`):
* - `rsp_callbacks`
* - `renderer_callbacks`
*
* It must be called only once and it must be called before `ultramodern::preinit`.
*/
void start(
ultramodern::renderer::WindowHandle window_handle,
const recomp::rsp::callbacks_t& rsp_callbacks,
const ultramodern::renderer::callbacks_t& renderer_callbacks,
const ultramodern::audio_callbacks_t& audio_callbacks,
const ultramodern::input::callbacks_t& input_callbacks,
const ultramodern::gfx_callbacks_t& gfx_callbacks,
ultramodern::renderer::WindowHandle window_handle, const recomp::rsp::callbacks_t& rsp_callbacks,
const ultramodern::renderer::callbacks_t& renderer_callbacks, const ultramodern::audio_callbacks_t& audio_callbacks,
const ultramodern::input::callbacks_t& input_callbacks, const ultramodern::gfx_callbacks_t& gfx_callbacks,
const ultramodern::events::callbacks_t& events_callbacks,
const ultramodern::error_handling::callbacks_t& error_handling_callbacks_
);
const ultramodern::error_handling::callbacks_t& error_handling_callbacks_);
void start_game(const std::u8string& game_id);
std::u8string current_game_id();
}
void start_game(const std::u8string& game_id);
std::u8string current_game_id();
} // namespace recomp
#endif

View file

@ -5,7 +5,7 @@
#include <ultramodern/ultra64.h>
template<int index, typename T>
T _arg(uint8_t* rdram, recomp_context* ctx) {
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>) {
@ -15,13 +15,14 @@ T _arg(uint8_t* rdram, recomp_context* ctx) {
}
else {
// static_assert in else workaround
[] <bool flag = false>() {
[]<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");
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>) {
@ -30,14 +31,15 @@ T _arg(uint8_t* rdram, recomp_context* ctx) {
}
else {
// static_assert in else workaround
[] <bool flag = false>() {
[]<bool flag = false>() {
static_assert(flag, "Unsupported type");
}();
}
();
}
}
template <typename T>
void _return(recomp_context* ctx, T val) {
template<typename T>
void _return(recomp_context *ctx, T val) {
static_assert(sizeof(T) <= 4 && "Only 32-bit value returns supported currently");
if constexpr (std::is_same_v<T, float>) {
ctx->f0.fl = val;
@ -47,9 +49,10 @@ void _return(recomp_context* ctx, T val) {
}
else {
// static_assert in else workaround
[] <bool flag = false>() {
[]<bool flag = false>() {
static_assert(flag, "Unsupported type");
}();
}
();
}
}

View file

@ -1,30 +1,30 @@
#ifndef __RECOMP_OVERLAYS_H__
#define __RECOMP_OVERLAYS_H__
#include <cstdint>
#include "sections.h"
#include <cstdint>
namespace recomp {
namespace overlays {
struct overlay_section_table_data_t {
SectionTableEntry* code_sections;
SectionTableEntry *code_sections;
size_t num_code_sections;
size_t total_num_sections;
};
struct overlays_by_index_t {
int* table;
int *table;
size_t len;
};
void register_overlays(const overlay_section_table_data_t& sections, const overlays_by_index_t& overlays);
void register_patches(const char* patch_data, std::size_t patch_size, SectionTableEntry* code_sections);
void read_patch_data(uint8_t* rdram, gpr patch_data_address);
void register_patches(const char *patch_data, std::size_t patch_size, SectionTableEntry *code_sections);
void read_patch_data(uint8_t *rdram, gpr patch_data_address);
void init_overlays();
}
};
} // namespace overlays
}; // namespace recomp
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);

View file

@ -3,8 +3,8 @@
#include <cstdio>
#include "rsp_vu.hpp"
#include "recomp.h"
#include "rsp_vu.hpp"
#include "ultramodern/ultra64.h"
// TODO: Move these to recomp namespace?
@ -17,36 +17,34 @@ enum class RspExitReason {
Unsupported
};
using RspUcodeFunc = RspExitReason(uint8_t* rdram);
using RspUcodeFunc = RspExitReason(uint8_t *rdram);
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_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))))
#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);
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];
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);
reinterpret_cast<uint8_t *>(&out)[(i + 2) ^ 3] = RSP_MEM_BU(offset + i, addr);
}
return out;
}
@ -54,32 +52,29 @@ static inline uint32_t RSP_MEM_HU_LOAD(uint32_t offset, uint32_t addr) {
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);
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];
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_ADD32(a, b) ((int32_t)((a) + (b)))
#define RSP_SUB32(a, b) \
((int32_t)((a) - (b)))
#define RSP_SUB32(a, b) ((int32_t)((a) - (b)))
#define RSP_SIGNED(val) \
((int32_t)(val))
#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) {
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);
@ -88,7 +83,7 @@ static inline void dma_rdram_to_dmem(uint8_t* rdram, uint32_t dmem_addr, uint32_
}
}
static inline void dma_dmem_to_rdram(uint8_t* rdram, uint32_t dmem_addr, uint32_t dram_addr, uint32_t wr_len) {
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);
@ -100,24 +95,26 @@ static inline void dma_dmem_to_rdram(uint8_t* rdram, uint32_t dmem_addr, uint32_
namespace recomp {
namespace rsp {
struct callbacks_t {
using get_rsp_microcode_t = RspUcodeFunc*(const OSTask* task);
using get_rsp_microcode_t = RspUcodeFunc *(const OSTask *task);
/**
* Return a function pointer to the corresponding RSP microcode function for the given `task_type`.
*
* The full OSTask (`task` parameter) is passed in case the `task_type` number is not enough information to distinguish out the exact microcode function.
* The full OSTask (`task` parameter) is passed in case the `task_type` number is not enough information to distinguish out the
* exact microcode function.
*
* This function is allowed to return `nullptr` if no microcode matches the specified task. In this case a message will be printed to stderr and the program will exit.
* This function is allowed to return `nullptr` if no microcode matches the specified task. In this case a message will be
* printed to stderr and the program will exit.
*/
get_rsp_microcode_t* get_rsp_microcode;
get_rsp_microcode_t *get_rsp_microcode;
};
void set_callbacks(const callbacks_t& callbacks);
void constants_init();
bool run_task(uint8_t* rdram, const OSTask* task);
}
}
bool run_task(uint8_t *rdram, const OSTask *task);
} // namespace rsp
} // namespace recomp
#endif

View file

@ -2,12 +2,13 @@
#define __SECTIONS_H__
#include <stdint.h>
#include "recomp.h"
#define ARRLEN(x) (sizeof(x) / sizeof((x)[0]))
typedef struct {
recomp_func_t* func;
recomp_func_t *func;
uint32_t offset;
} FuncEntry;

View file

@ -6,24 +6,24 @@
#define VI_NTSC_CLOCK 48681812
extern "C" void osAiSetFrequency_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osAiSetFrequency_recomp(uint8_t *rdram, recomp_context *ctx) {
uint32_t freq = ctx->r4;
// This makes actual audio frequency more accurate to console, but may not be desirable
//uint32_t dacRate = (uint32_t)(((float)VI_NTSC_CLOCK / freq) + 0.5f);
//freq = VI_NTSC_CLOCK / dacRate;
// uint32_t dacRate = (uint32_t)(((float)VI_NTSC_CLOCK / freq) + 0.5f);
// freq = VI_NTSC_CLOCK / dacRate;
ctx->r2 = freq;
ultramodern::set_audio_frequency(freq);
}
extern "C" void osAiSetNextBuffer_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osAiSetNextBuffer_recomp(uint8_t *rdram, recomp_context *ctx) {
ultramodern::queue_audio_buffer(rdram, ctx->r4, ctx->r5);
ctx->r2 = 0;
}
extern "C" void osAiGetLength_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osAiGetLength_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = ultramodern::get_remaining_audio_bytes();
}
extern "C" void osAiGetStatus_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osAiGetStatus_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = 0x00000000; // Pretend the audio DMAs finish instantly
}

View file

@ -4,15 +4,15 @@
#define MAXCONTROLLERS 4
extern "C" void recomp_set_current_frame_poll_id(uint8_t* rdram, recomp_context* ctx) {
extern "C" void recomp_set_current_frame_poll_id(uint8_t *rdram, recomp_context *ctx) {
// TODO reimplement the system for tagging polls with IDs to handle games with multithreaded input polling.
}
extern "C" void recomp_measure_latency(uint8_t* rdram, recomp_context* ctx) {
extern "C" void recomp_measure_latency(uint8_t *rdram, recomp_context *ctx) {
ultramodern::measure_input_latency();
}
extern "C" void osContInit_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osContInit_recomp(uint8_t *rdram, recomp_context *ctx) {
PTR(OSMesgQueue) mq = _arg<0, PTR(OSMesgQueue)>(rdram, ctx);
PTR(u8) bitpattern = _arg<1, PTR(u8)>(rdram, ctx);
PTR(OSContStatus) data = _arg<2, PTR(OSContStatus)>(rdram, ctx);
@ -22,7 +22,7 @@ extern "C" void osContInit_recomp(uint8_t* rdram, recomp_context* ctx) {
_return<s32>(ctx, ret);
}
extern "C" void osContReset_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osContReset_recomp(uint8_t *rdram, recomp_context *ctx) {
PTR(OSMesgQueue) mq = _arg<0, PTR(OSMesgQueue)>(rdram, ctx);
PTR(OSContStatus) data = _arg<1, PTR(OSContStatus)>(rdram, ctx);
@ -31,7 +31,7 @@ extern "C" void osContReset_recomp(uint8_t* rdram, recomp_context* ctx) {
_return<s32>(ctx, ret);
}
extern "C" void osContStartReadData_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osContStartReadData_recomp(uint8_t *rdram, recomp_context *ctx) {
PTR(OSMesgQueue) mq = _arg<0, PTR(OSMesgQueue)>(rdram, ctx);
s32 ret = osContStartReadData(PASS_RDRAM mq);
@ -39,7 +39,7 @@ extern "C" void osContStartReadData_recomp(uint8_t* rdram, recomp_context* ctx)
_return<s32>(ctx, ret);
}
extern "C" void osContGetReadData_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osContGetReadData_recomp(uint8_t *rdram, recomp_context *ctx) {
PTR(OSContPad) data = _arg<0, PTR(OSContPad)>(rdram, ctx);
OSContPad dummy_data[MAXCONTROLLERS];
@ -54,7 +54,7 @@ extern "C" void osContGetReadData_recomp(uint8_t* rdram, recomp_context* ctx) {
}
}
extern "C" void osContStartQuery_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osContStartQuery_recomp(uint8_t *rdram, recomp_context *ctx) {
PTR(OSMesgQueue) mq = _arg<0, PTR(OSMesgQueue)>(rdram, ctx);
s32 ret = osContStartQuery(PASS_RDRAM mq);
@ -62,13 +62,13 @@ extern "C" void osContStartQuery_recomp(uint8_t * rdram, recomp_context * ctx) {
_return<s32>(ctx, ret);
}
extern "C" void osContGetQuery_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osContGetQuery_recomp(uint8_t *rdram, recomp_context *ctx) {
PTR(OSContStatus) data = _arg<0, PTR(OSContStatus)>(rdram, ctx);
osContGetQuery(PASS_RDRAM data);
}
extern "C" void osContSetCh_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osContSetCh_recomp(uint8_t *rdram, recomp_context *ctx) {
u8 ch = _arg<0, u8>(rdram, ctx);
s32 ret = osContSetCh(PASS_RDRAM ch);
@ -76,7 +76,7 @@ extern "C" void osContSetCh_recomp(uint8_t* rdram, recomp_context* ctx) {
_return<s32>(ctx, ret);
}
extern "C" void __osMotorAccess_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void __osMotorAccess_recomp(uint8_t *rdram, recomp_context *ctx) {
PTR(OSPfs) pfs = _arg<0, PTR(OSPfs)>(rdram, ctx);
s32 flag = _arg<1, s32>(rdram, ctx);
@ -85,7 +85,7 @@ extern "C" void __osMotorAccess_recomp(uint8_t* rdram, recomp_context* ctx) {
_return<s32>(ctx, ret);
}
extern "C" void osMotorInit_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osMotorInit_recomp(uint8_t *rdram, recomp_context *ctx) {
PTR(OSMesgQueue) mq = _arg<0, PTR(OSMesgQueue)>(rdram, ctx);
PTR(OSPfs) pfs = _arg<1, PTR(OSPfs)>(rdram, ctx);
int channel = _arg<2, s32>(rdram, ctx);
@ -95,7 +95,7 @@ extern "C" void osMotorInit_recomp(uint8_t* rdram, recomp_context* ctx) {
_return<s32>(ctx, ret);
}
extern "C" void osMotorStart_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osMotorStart_recomp(uint8_t *rdram, recomp_context *ctx) {
PTR(OSPfs) pfs = _arg<0, PTR(OSPfs)>(rdram, ctx);
s32 ret = osMotorStart(PASS_RDRAM pfs);
@ -103,7 +103,7 @@ extern "C" void osMotorStart_recomp(uint8_t* rdram, recomp_context* ctx) {
_return<s32>(ctx, ret);
}
extern "C" void osMotorStop_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osMotorStop_recomp(uint8_t *rdram, recomp_context *ctx) {
PTR(OSPfs) pfs = _arg<0, PTR(OSPfs)>(rdram, ctx);
s32 ret = osMotorStop(PASS_RDRAM pfs);

View file

@ -29,15 +29,15 @@ constexpr void update_bit(uint32_t& state, uint32_t flags, RDPStatusBit bit) {
uint32_t rdp_state = 1 << (int)RDPStatusBit::BufferReady;
extern "C" void osDpSetNextBuffer_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osDpSetNextBuffer_recomp(uint8_t *rdram, recomp_context *ctx) {
assert(false);
}
extern "C" void osDpGetStatus_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osDpGetStatus_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = rdp_state;
}
extern "C" void osDpSetStatus_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osDpSetStatus_recomp(uint8_t *rdram, recomp_context *ctx) {
update_bit(rdp_state, ctx->r4, RDPStatusBit::XbusDmem);
update_bit(rdp_state, ctx->r4, RDPStatusBit::Freeze);
update_bit(rdp_state, ctx->r4, RDPStatusBit::Flush);

View file

@ -11,15 +11,15 @@ constexpr int eep4_block_count = eep4_size / eeprom_block_size;
constexpr int eep16_size = 16384;
constexpr int eep16_block_count = eep16_size / eeprom_block_size;
extern "C" void osEepromProbe_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osEepromProbe_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = 0x02; // EEP16K
}
extern "C" void osEepromWrite_recomp(uint8_t* rdram, recomp_context* ctx) {
assert(false);// ctx->r2 = 8; // CONT_NO_RESPONSE_ERROR
extern "C" void osEepromWrite_recomp(uint8_t *rdram, recomp_context *ctx) {
assert(false); // ctx->r2 = 8; // CONT_NO_RESPONSE_ERROR
}
extern "C" void osEepromLongWrite_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osEepromLongWrite_recomp(uint8_t *rdram, recomp_context *ctx) {
uint8_t eep_address = ctx->r5;
gpr buffer = ctx->r6;
int32_t nbytes = ctx->r7;
@ -32,11 +32,11 @@ extern "C" void osEepromLongWrite_recomp(uint8_t* rdram, recomp_context* ctx) {
ctx->r2 = 0;
}
extern "C" void osEepromRead_recomp(uint8_t* rdram, recomp_context* ctx) {
assert(false);// ctx->r2 = 8; // CONT_NO_RESPONSE_ERROR
extern "C" void osEepromRead_recomp(uint8_t *rdram, recomp_context *ctx) {
assert(false); // ctx->r2 = 8; // CONT_NO_RESPONSE_ERROR
}
extern "C" void osEepromLongRead_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osEepromLongRead_recomp(uint8_t *rdram, recomp_context *ctx) {
uint8_t eep_address = ctx->r5;
gpr buffer = ctx->r6;
int32_t nbytes = ctx->r7;

View file

@ -4,13 +4,13 @@ constexpr std::u8string_view backup_suffix = u8".bak";
constexpr std::u8string_view temp_suffix = u8".temp";
std::ifstream recomp::open_input_backup_file(const std::filesystem::path& filepath, std::ios_base::openmode mode) {
std::filesystem::path backup_path{filepath};
std::filesystem::path backup_path{ filepath };
backup_path += backup_suffix;
return std::ifstream{backup_path, mode};
return std::ifstream{ backup_path, mode };
}
std::ifstream recomp::open_input_file_with_backup(const std::filesystem::path& filepath, std::ios_base::openmode mode) {
std::ifstream ret{filepath, mode};
std::ifstream ret{ filepath, mode };
// Check if the file failed to open and open the corresponding backup file instead if so.
if (!ret.good()) {
@ -21,7 +21,7 @@ std::ifstream recomp::open_input_file_with_backup(const std::filesystem::path& f
}
std::ofstream recomp::open_output_file_with_backup(const std::filesystem::path& filepath, std::ios_base::openmode mode) {
std::filesystem::path temp_path{filepath};
std::filesystem::path temp_path{ filepath };
temp_path += temp_suffix;
std::ofstream temp_file_out{ temp_path, mode };
@ -29,10 +29,10 @@ std::ofstream recomp::open_output_file_with_backup(const std::filesystem::path&
}
bool recomp::finalize_output_file_with_backup(const std::filesystem::path& filepath) {
std::filesystem::path backup_path{filepath};
std::filesystem::path backup_path{ filepath };
backup_path += backup_suffix;
std::filesystem::path temp_path{filepath};
std::filesystem::path temp_path{ filepath };
temp_path += temp_suffix;
std::error_code ec;

View file

@ -1,7 +1,9 @@
#include <array>
#include <cassert>
#include <ultramodern/ultra64.h>
#include <ultramodern/ultramodern.hpp>
#include "recomp.h"
// TODO move this out into ultramodern code
@ -13,24 +15,24 @@ constexpr uint32_t page_count = flash_size / page_size;
constexpr uint32_t sector_size = page_size * pages_per_sector;
constexpr uint32_t sector_count = flash_size / sector_size;
void save_write_ptr(const void* in, uint32_t offset, uint32_t count);
void save_write_ptr(const void *in, uint32_t offset, uint32_t count);
void save_write(RDRAM_ARG PTR(void) rdram_address, uint32_t offset, uint32_t count);
void save_read(RDRAM_ARG PTR(void) rdram_address, uint32_t offset, uint32_t count);
void save_clear(uint32_t start, uint32_t size, char value);
std::array<char, page_size> write_buffer;
extern "C" void osFlashInit_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osFlashInit_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = ultramodern::flash_handle;
}
extern "C" void osFlashReadStatus_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osFlashReadStatus_recomp(uint8_t *rdram, recomp_context *ctx) {
PTR(u8) flash_status = ctx->r4;
MEM_B(0, flash_status) = 0;
}
extern "C" void osFlashReadId_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osFlashReadId_recomp(uint8_t *rdram, recomp_context *ctx) {
PTR(u32) flash_type = ctx->r4;
PTR(u32) flash_maker = ctx->r5;
@ -39,24 +41,23 @@ extern "C" void osFlashReadId_recomp(uint8_t * rdram, recomp_context * ctx) {
MEM_W(0, flash_maker) = 0x00C2001E;
}
extern "C" void osFlashClearStatus_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osFlashClearStatus_recomp(uint8_t *rdram, recomp_context *ctx) {
}
extern "C" void osFlashAllErase_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osFlashAllErase_recomp(uint8_t *rdram, recomp_context *ctx) {
save_clear(0, ultramodern::save_size, 0xFF);
ctx->r2 = 0;
}
extern "C" void osFlashAllEraseThrough_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osFlashAllEraseThrough_recomp(uint8_t *rdram, recomp_context *ctx) {
save_clear(0, ultramodern::save_size, 0xFF);
ctx->r2 = 0;
}
// This function is named sector but really means page.
extern "C" void osFlashSectorErase_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osFlashSectorErase_recomp(uint8_t *rdram, recomp_context *ctx) {
uint32_t page_num = (uint32_t)ctx->r4;
// Prevent out of bounds erase
@ -71,7 +72,7 @@ extern "C" void osFlashSectorErase_recomp(uint8_t * rdram, recomp_context * ctx)
}
// Same naming issue as above.
extern "C" void osFlashSectorEraseThrough_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osFlashSectorEraseThrough_recomp(uint8_t *rdram, recomp_context *ctx) {
uint32_t page_num = (uint32_t)ctx->r4;
// Prevent out of bounds erase
@ -85,17 +86,17 @@ extern "C" void osFlashSectorEraseThrough_recomp(uint8_t * rdram, recomp_context
ctx->r2 = 0;
}
extern "C" void osFlashCheckEraseEnd_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osFlashCheckEraseEnd_recomp(uint8_t *rdram, recomp_context *ctx) {
// All erases are blocking in this implementation, so this should always return OK.
ctx->r2 = 0; // FLASH_STATUS_ERASE_OK
}
extern "C" void osFlashWriteBuffer_recomp(uint8_t * rdram, recomp_context * ctx) {
OSIoMesg* mb = TO_PTR(OSIoMesg, ctx->r4);
extern "C" void osFlashWriteBuffer_recomp(uint8_t *rdram, recomp_context *ctx) {
OSIoMesg *mb = TO_PTR(OSIoMesg, ctx->r4);
int32_t pri = ctx->r5;
PTR(void) dramAddr = ctx->r6;
PTR(OSMesgQueue) mq = ctx->r7;
// Copy the input data into the write buffer
for (size_t i = 0; i < page_size; i++) {
write_buffer[i] = MEM_B(i, dramAddr);
@ -107,7 +108,7 @@ extern "C" void osFlashWriteBuffer_recomp(uint8_t * rdram, recomp_context * ctx)
ctx->r2 = 0;
}
extern "C" void osFlashWriteArray_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osFlashWriteArray_recomp(uint8_t *rdram, recomp_context *ctx) {
uint32_t page_num = ctx->r4;
// Copy the write buffer into the save file
@ -116,8 +117,8 @@ extern "C" void osFlashWriteArray_recomp(uint8_t * rdram, recomp_context * ctx)
ctx->r2 = 0;
}
extern "C" void osFlashReadArray_recomp(uint8_t * rdram, recomp_context * ctx) {
OSIoMesg* mb = TO_PTR(OSIoMesg, ctx->r4);
extern "C" void osFlashReadArray_recomp(uint8_t *rdram, recomp_context *ctx) {
OSIoMesg *mb = TO_PTR(OSIoMesg, ctx->r4);
int32_t pri = ctx->r5;
uint32_t page_num = ctx->r6;
PTR(void) dramAddr = ctx->r7;
@ -136,6 +137,6 @@ extern "C" void osFlashReadArray_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = 0;
}
extern "C" void osFlashChange_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osFlashChange_recomp(uint8_t *rdram, recomp_context *ctx) {
assert(false);
}

View file

@ -1,10 +1,11 @@
#include <ultramodern/ultramodern.hpp>
#include "recomp.h"
// TODO remove these by implementing the necessary instructions and control flow handling in the recompiler.
// This has already been partially completed.
extern "C" void __udivdi3_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void __udivdi3_recomp(uint8_t *rdram, recomp_context *ctx) {
uint64_t a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu);
uint64_t b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu);
uint64_t ret = a / b;
@ -13,7 +14,7 @@ extern "C" void __udivdi3_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r3 = (int32_t)(ret >> 0);
}
extern "C" void __divdi3_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void __divdi3_recomp(uint8_t *rdram, recomp_context *ctx) {
int64_t a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu);
int64_t b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu);
int64_t ret = a / b;
@ -22,7 +23,7 @@ extern "C" void __divdi3_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r3 = (int32_t)(ret >> 0);
}
extern "C" void __umoddi3_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void __umoddi3_recomp(uint8_t *rdram, recomp_context *ctx) {
uint64_t a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu);
uint64_t b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu);
uint64_t ret = a % b;
@ -31,7 +32,7 @@ extern "C" void __umoddi3_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r3 = (int32_t)(ret >> 0);
}
extern "C" void __ull_div_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void __ull_div_recomp(uint8_t *rdram, recomp_context *ctx) {
uint64_t a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu);
uint64_t b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu);
uint64_t ret = a / b;
@ -40,7 +41,7 @@ extern "C" void __ull_div_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r3 = (int32_t)(ret >> 0);
}
extern "C" void __ll_div_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void __ll_div_recomp(uint8_t *rdram, recomp_context *ctx) {
int64_t a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu);
int64_t b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu);
int64_t ret = a / b;
@ -49,7 +50,7 @@ extern "C" void __ll_div_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r3 = (int32_t)(ret >> 0);
}
extern "C" void __ll_mul_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void __ll_mul_recomp(uint8_t *rdram, recomp_context *ctx) {
uint64_t a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu);
uint64_t b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu);
uint64_t ret = a * b;
@ -58,7 +59,7 @@ extern "C" void __ll_mul_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r3 = (int32_t)(ret >> 0);
}
extern "C" void __ull_rem_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void __ull_rem_recomp(uint8_t *rdram, recomp_context *ctx) {
uint64_t a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu);
uint64_t b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu);
uint64_t ret = a % b;
@ -67,14 +68,14 @@ extern "C" void __ull_rem_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r3 = (int32_t)(ret >> 0);
}
extern "C" void __ull_to_d_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void __ull_to_d_recomp(uint8_t *rdram, recomp_context *ctx) {
uint64_t a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu);
double ret = (double)a;
ctx->f0.d = ret;
}
extern "C" void __ull_to_f_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void __ull_to_f_recomp(uint8_t *rdram, recomp_context *ctx) {
uint64_t a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu);
float ret = (float)a;

View file

@ -7,14 +7,14 @@
#include "ultramodern/ultramodern.hpp"
#include "recomp.h"
#include "overlays.hpp"
#include "recomp.h"
#include "sections.h"
static recomp::overlays::overlay_section_table_data_t sections_info {};
static recomp::overlays::overlays_by_index_t overlays_info {};
static recomp::overlays::overlay_section_table_data_t sections_info{};
static recomp::overlays::overlays_by_index_t overlays_info{};
static SectionTableEntry* patch_code_sections = nullptr;
static SectionTableEntry *patch_code_sections = nullptr;
static std::vector<char> patch_data;
void recomp::overlays::register_overlays(const overlay_section_table_data_t& sections, const overlays_by_index_t& overlays) {
@ -22,7 +22,7 @@ void recomp::overlays::register_overlays(const overlay_section_table_data_t& sec
overlays_info = overlays;
}
void recomp::overlays::register_patches(const char* patch, std::size_t size, SectionTableEntry* sections) {
void recomp::overlays::register_patches(const char *patch, std::size_t size, SectionTableEntry *sections) {
patch_code_sections = sections;
patch_data.resize(size);
@ -44,7 +44,7 @@ struct LoadedSection {
};
std::vector<LoadedSection> loaded_sections{};
std::unordered_map<int32_t, recomp_func_t*> func_map{};
std::unordered_map<int32_t, recomp_func_t *> func_map{};
void load_overlay(size_t section_table_index, int32_t ram) {
const SectionTableEntry& section = sections_info.code_sections[section_table_index];
@ -73,29 +73,29 @@ static void load_patch_functions() {
load_special_overlay(patch_code_sections[0], patch_code_sections[0].ram_addr);
}
void recomp::overlays::read_patch_data(uint8_t* rdram, gpr patch_data_address) {
void recomp::overlays::read_patch_data(uint8_t *rdram, gpr patch_data_address) {
for (size_t i = 0; i < patch_data.size(); i++) {
MEM_B(i, patch_data_address) = patch_data[i];
}
}
extern "C" {
int32_t* section_addresses = nullptr;
int32_t *section_addresses = nullptr;
}
extern "C" void load_overlays(uint32_t rom, int32_t ram_addr, uint32_t size) {
// Search for the first section that's included in the loaded rom range
// Sections were sorted by `init_overlays` so we can use the bounds functions
auto lower = std::lower_bound(&sections_info.code_sections[0], &sections_info.code_sections[sections_info.num_code_sections], rom,
auto lower = std::lower_bound(
&sections_info.code_sections[0], &sections_info.code_sections[sections_info.num_code_sections], rom,
[](const SectionTableEntry& entry, uint32_t addr) {
return entry.rom_addr < addr;
}
);
auto upper = std::upper_bound(&sections_info.code_sections[0], &sections_info.code_sections[sections_info.num_code_sections], (uint32_t)(rom + size),
});
auto upper = std::upper_bound(
&sections_info.code_sections[0], &sections_info.code_sections[sections_info.num_code_sections], (uint32_t)(rom + size),
[](uint32_t addr, const SectionTableEntry& entry) {
return addr < entry.size + entry.rom_addr;
}
);
});
// Load the overlays that were found
for (auto it = lower; it != upper; ++it) {
load_overlay(std::distance(&sections_info.code_sections[0], it), it->rom_addr - rom + ram_addr);
@ -106,7 +106,9 @@ extern "C" void unload_overlay_by_id(uint32_t id) {
uint32_t section_table_index = overlays_info.table[id];
const SectionTableEntry& section = sections_info.code_sections[section_table_index];
auto find_it = std::find_if(loaded_sections.begin(), loaded_sections.end(), [section_table_index](const LoadedSection& s) { return s.section_table_index == section_table_index; });
auto find_it = std::find_if(loaded_sections.begin(), loaded_sections.end(), [section_table_index](const LoadedSection& s) {
return s.section_table_index == section_table_index;
});
if (find_it != loaded_sections.end()) {
// Determine where each function was loaded to and remove that entry from the function map
@ -144,11 +146,12 @@ extern "C" void unload_overlays(int32_t ram_addr, uint32_t size) {
if (ram_addr < (it->loaded_ram_addr + section.size) && (ram_addr + size) >= it->loaded_ram_addr) {
// Check if the section isn't entirely in the loaded region
if (ram_addr > it->loaded_ram_addr || (ram_addr + size) < (it->loaded_ram_addr + section.size)) {
fprintf(stderr,
fprintf(
stderr,
"Cannot partially unload section\n"
" rom: 0x%08X size: 0x%08X loaded_addr: 0x%08X\n"
" unloaded_ram: 0x%08X unloaded_size : 0x%08X\n",
section.rom_addr, section.size, it->loaded_ram_addr, ram_addr, size);
section.rom_addr, section.size, it->loaded_ram_addr, ram_addr, size);
assert(false);
std::exit(EXIT_FAILURE);
}
@ -177,16 +180,16 @@ void recomp::overlays::init_overlays() {
}
// Sort the executable sections by rom address
std::sort(&sections_info.code_sections[0], &sections_info.code_sections[sections_info.num_code_sections],
std::sort(
&sections_info.code_sections[0], &sections_info.code_sections[sections_info.num_code_sections],
[](const SectionTableEntry& a, const SectionTableEntry& b) {
return a.rom_addr < b.rom_addr;
}
);
});
load_patch_functions();
}
extern "C" recomp_func_t * get_function(int32_t addr) {
extern "C" recomp_func_t *get_function(int32_t addr) {
auto func_find = func_map.find(addr);
if (func_find == func_map.end()) {
fprintf(stderr, "Failed to find function at 0x%08X\n", addr);
@ -195,4 +198,3 @@ extern "C" recomp_func_t * get_function(int32_t addr) {
}
return func_find->second;
}

View file

@ -2,34 +2,34 @@
#include <ultramodern/ultra64.h>
#include <ultramodern/ultramodern.hpp>
extern "C" void osPfsInitPak_recomp(uint8_t * rdram, recomp_context* ctx) {
extern "C" void osPfsInitPak_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK
}
extern "C" void osPfsFreeBlocks_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osPfsFreeBlocks_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK
}
extern "C" void osPfsAllocateFile_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osPfsAllocateFile_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK
}
extern "C" void osPfsDeleteFile_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osPfsDeleteFile_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK
}
extern "C" void osPfsFileState_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osPfsFileState_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK
}
extern "C" void osPfsFindFile_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osPfsFindFile_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK
}
extern "C" void osPfsReadWriteFile_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osPfsReadWriteFile_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK
}
extern "C" void osPfsChecker_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osPfsChecker_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK
}

View file

@ -1,15 +1,17 @@
#include <memory>
#include <fstream>
#include <array>
#include <cstring>
#include <string>
#include <fstream>
#include <memory>
#include <mutex>
#include "recomp.h"
#include "game.hpp"
#include "files.hpp"
#include <string>
#include <ultramodern/ultra64.h>
#include <ultramodern/ultramodern.hpp>
#include "files.hpp"
#include "game.hpp"
#include "recomp.h"
static std::vector<uint8_t> rom;
bool recomp::is_rom_loaded() {
@ -35,14 +37,14 @@ constexpr uint32_t phys_to_k1(uint32_t addr) {
return addr | 0xA0000000;
}
extern "C" void __osPiGetAccess_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void __osPiGetAccess_recomp(uint8_t *rdram, recomp_context *ctx) {
}
extern "C" void __osPiRelAccess_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void __osPiRelAccess_recomp(uint8_t *rdram, recomp_context *ctx) {
}
extern "C" void osCartRomInit_recomp(uint8_t* rdram, recomp_context* ctx) {
OSPiHandle* handle = TO_PTR(OSPiHandle, ultramodern::cart_handle);
extern "C" void osCartRomInit_recomp(uint8_t *rdram, recomp_context *ctx) {
OSPiHandle *handle = TO_PTR(OSPiHandle, ultramodern::cart_handle);
handle->type = 0; // cart
handle->baseAddress = phys_to_k1(rom_base);
handle->domain = 0;
@ -50,8 +52,8 @@ extern "C" void osCartRomInit_recomp(uint8_t* rdram, recomp_context* ctx) {
ctx->r2 = (gpr)ultramodern::cart_handle;
}
extern "C" void osDriveRomInit_recomp(uint8_t * rdram, recomp_context * ctx) {
OSPiHandle* handle = TO_PTR(OSPiHandle, ultramodern::drive_handle);
extern "C" void osDriveRomInit_recomp(uint8_t *rdram, recomp_context *ctx) {
OSPiHandle *handle = TO_PTR(OSPiHandle, ultramodern::drive_handle);
handle->type = 1; // bulk
handle->baseAddress = phys_to_k1(drive_base);
handle->domain = 0;
@ -59,28 +61,28 @@ extern "C" void osDriveRomInit_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = (gpr)ultramodern::drive_handle;
}
extern "C" void osCreatePiManager_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osCreatePiManager_recomp(uint8_t *rdram, recomp_context *ctx) {
;
}
void recomp::do_rom_read(uint8_t* rdram, gpr ram_address, uint32_t physical_addr, size_t num_bytes) {
void recomp::do_rom_read(uint8_t *rdram, gpr ram_address, uint32_t physical_addr, size_t num_bytes) {
// TODO use word copies when possible
// TODO handle misaligned DMA
assert((physical_addr & 0x1) == 0 && "Only PI DMA from aligned ROM addresses is currently supported");
assert((ram_address & 0x7) == 0 && "Only PI DMA to aligned RDRAM addresses is currently supported");
assert((num_bytes & 0x1) == 0 && "Only PI DMA with aligned sizes is currently supported");
uint8_t* rom_addr = rom.data() + physical_addr - rom_base;
uint8_t *rom_addr = rom.data() + physical_addr - rom_base;
for (size_t i = 0; i < num_bytes; i++) {
MEM_B(i, ram_address) = *rom_addr;
rom_addr++;
}
}
void recomp::do_rom_pio(uint8_t* rdram, gpr ram_address, uint32_t physical_addr) {
void recomp::do_rom_pio(uint8_t *rdram, gpr ram_address, uint32_t physical_addr) {
assert((physical_addr & 0x3) == 0 && "PIO not 4-byte aligned in device, currently unsupported");
assert((ram_address & 0x3) == 0 && "PIO not 4-byte aligned in RDRAM, currently unsupported");
uint8_t* rom_addr = rom.data() + physical_addr - rom_base;
uint8_t *rom_addr = rom.data() + physical_addr - rom_base;
MEM_B(0, ram_address) = *rom_addr++;
MEM_B(1, ram_address) = *rom_addr++;
MEM_B(2, ram_address) = *rom_addr++;
@ -99,7 +101,7 @@ const std::u8string save_folder = u8"saves";
extern std::filesystem::path config_path;
std::filesystem::path get_save_file_path() {
return config_path / save_folder / (std::u8string{recomp::current_game_id()} + u8".bin");
return config_path / save_folder / (std::u8string{ recomp::current_game_id() } + u8".bin");
}
void update_save_file() {
@ -119,7 +121,8 @@ void update_save_file() {
saving_failed = !recomp::finalize_output_file_with_backup(get_save_file_path());
}
if (saving_failed) {
ultramodern::error_handling::message_box("Failed to write to the save file. Check your file permissions and whether the save folder has been moved to Dropbox or similar, as this can cause issues.");
ultramodern::error_handling::message_box("Failed to write to the save file. Check your file permissions and whether the save "
"folder has been moved to Dropbox or similar, as this can cause issues.");
}
}
@ -148,18 +151,18 @@ void saving_thread_func(RDRAM_ARG1) {
}
}
void save_write_ptr(const void* in, uint32_t offset, uint32_t count) {
void save_write_ptr(const void *in, uint32_t offset, uint32_t count) {
{
std::lock_guard lock { save_context.save_buffer_mutex };
std::lock_guard lock{ save_context.save_buffer_mutex };
memcpy(&save_context.save_buffer[offset], in, count);
}
save_context.write_sempahore.signal();
}
void save_write(RDRAM_ARG PTR(void) rdram_address, uint32_t offset, uint32_t count) {
{
std::lock_guard lock { save_context.save_buffer_mutex };
std::lock_guard lock{ save_context.save_buffer_mutex };
for (uint32_t i = 0; i < count; i++) {
save_context.save_buffer[offset + i] = MEM_B(i, rdram_address);
}
@ -169,7 +172,7 @@ void save_write(RDRAM_ARG PTR(void) rdram_address, uint32_t offset, uint32_t cou
}
void save_read(RDRAM_ARG PTR(void) rdram_address, uint32_t offset, uint32_t count) {
std::lock_guard lock { save_context.save_buffer_mutex };
std::lock_guard lock{ save_context.save_buffer_mutex };
for (size_t i = 0; i < count; i++) {
MEM_B(i, rdram_address) = save_context.save_buffer[offset + i];
}
@ -177,7 +180,7 @@ void save_read(RDRAM_ARG PTR(void) rdram_address, uint32_t offset, uint32_t coun
void save_clear(uint32_t start, uint32_t size, char value) {
{
std::lock_guard lock { save_context.save_buffer_mutex };
std::lock_guard lock{ save_context.save_buffer_mutex };
std::fill_n(save_context.save_buffer.begin() + start, size, value);
}
@ -200,7 +203,7 @@ void ultramodern::init_saving(RDRAM_ARG1) {
save_context.save_buffer.fill(0);
}
save_context.saving_thread = std::thread{saving_thread_func, PASS_RDRAM};
save_context.saving_thread = std::thread{ saving_thread_func, PASS_RDRAM };
}
void ultramodern::join_saving_thread() {
@ -217,32 +220,37 @@ void do_dma(RDRAM_ARG PTR(OSMesgQueue) mq, gpr rdram_address, uint32_t physical_
// Send a message to the mq to indicate that the transfer completed
osSendMesg(rdram, mq, 0, OS_MESG_NOBLOCK);
} else if (physical_addr >= sram_base) {
}
else if (physical_addr >= sram_base) {
// read sram
save_read(rdram, rdram_address, physical_addr - sram_base, size);
// Send a message to the mq to indicate that the transfer completed
osSendMesg(rdram, mq, 0, OS_MESG_NOBLOCK);
} else {
}
else {
fprintf(stderr, "[WARN] PI DMA read from unknown region, phys address 0x%08X\n", physical_addr);
}
} else {
}
else {
if (physical_addr >= rom_base) {
// write cart rom
throw std::runtime_error("ROM DMA write unimplemented");
} else if (physical_addr >= sram_base) {
}
else if (physical_addr >= sram_base) {
// write sram
save_write(rdram, rdram_address, physical_addr - sram_base, size);
// Send a message to the mq to indicate that the transfer completed
osSendMesg(rdram, mq, 0, OS_MESG_NOBLOCK);
} else {
}
else {
fprintf(stderr, "[WARN] PI DMA write to unknown region, phys address 0x%08X\n", physical_addr);
}
}
}
extern "C" void osPiStartDma_recomp(RDRAM_ARG recomp_context* ctx) {
extern "C" void osPiStartDma_recomp(RDRAM_ARG recomp_context *ctx) {
uint32_t mb = ctx->r4;
uint32_t pri = ctx->r5;
uint32_t direction = ctx->r6;
@ -259,9 +267,9 @@ extern "C" void osPiStartDma_recomp(RDRAM_ARG recomp_context* ctx) {
ctx->r2 = 0;
}
extern "C" void osEPiStartDma_recomp(RDRAM_ARG recomp_context* ctx) {
OSPiHandle* handle = TO_PTR(OSPiHandle, ctx->r4);
OSIoMesg* mb = TO_PTR(OSIoMesg, ctx->r5);
extern "C" void osEPiStartDma_recomp(RDRAM_ARG recomp_context *ctx) {
OSPiHandle *handle = TO_PTR(OSPiHandle, ctx->r4);
OSIoMesg *mb = TO_PTR(OSIoMesg, ctx->r5);
uint32_t direction = ctx->r6;
uint32_t devAddr = handle->baseAddress | mb->devAddr;
gpr dramAddr = mb->dramAddr;
@ -276,8 +284,8 @@ extern "C" void osEPiStartDma_recomp(RDRAM_ARG recomp_context* ctx) {
ctx->r2 = 0;
}
extern "C" void osEPiReadIo_recomp(RDRAM_ARG recomp_context * ctx) {
OSPiHandle* handle = TO_PTR(OSPiHandle, ctx->r4);
extern "C" void osEPiReadIo_recomp(RDRAM_ARG recomp_context *ctx) {
OSPiHandle *handle = TO_PTR(OSPiHandle, ctx->r4);
uint32_t devAddr = handle->baseAddress | ctx->r5;
gpr dramAddr = ctx->r6;
uint32_t physical_addr = k1_to_phys(devAddr);
@ -285,7 +293,8 @@ extern "C" void osEPiReadIo_recomp(RDRAM_ARG recomp_context * ctx) {
if (physical_addr > rom_base) {
// cart rom
recomp::do_rom_pio(PASS_RDRAM dramAddr, physical_addr);
} else {
}
else {
// sram
assert(false && "SRAM ReadIo unimplemented");
}
@ -293,10 +302,10 @@ extern "C" void osEPiReadIo_recomp(RDRAM_ARG recomp_context * ctx) {
ctx->r2 = 0;
}
extern "C" void osPiGetStatus_recomp(RDRAM_ARG recomp_context * ctx) {
extern "C" void osPiGetStatus_recomp(RDRAM_ARG recomp_context *ctx) {
ctx->r2 = 0;
}
extern "C" void osPiRawStartDma_recomp(RDRAM_ARG recomp_context * ctx) {
extern "C" void osPiRawStartDma_recomp(RDRAM_ARG recomp_context *ctx) {
ctx->r2 = 0;
}

View file

@ -2,34 +2,35 @@
#include <ultramodern/ultra64.h>
#include <ultramodern/ultramodern.hpp>
#include "recomp.h"
#include "euc-jp.hpp"
#include "recomp.h"
extern "C" void __checkHardware_msp_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void __checkHardware_msp_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = 0;
}
extern "C" void __checkHardware_kmc_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void __checkHardware_kmc_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = 0;
}
extern "C" void __checkHardware_isv_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void __checkHardware_isv_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = 0;
}
extern "C" void __osInitialize_msp_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void __osInitialize_msp_recomp(uint8_t *rdram, recomp_context *ctx) {
}
extern "C" void __osInitialize_kmc_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void __osInitialize_kmc_recomp(uint8_t *rdram, recomp_context *ctx) {
}
extern "C" void __osInitialize_isv_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void __osInitialize_isv_recomp(uint8_t *rdram, recomp_context *ctx) {
}
extern "C" void isPrintfInit_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void isPrintfInit_recomp(uint8_t *rdram, recomp_context *ctx) {
}
extern "C" void __osRdbSend_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void __osRdbSend_recomp(uint8_t *rdram, recomp_context *ctx) {
gpr buf = ctx->r4;
size_t size = ctx->r5;
u32 type = (u32)ctx->r6;
@ -45,16 +46,16 @@ extern "C" void __osRdbSend_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = size;
}
extern "C" void is_proutSyncPrintf_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void is_proutSyncPrintf_recomp(uint8_t *rdram, recomp_context *ctx) {
// Buffering to speed up print performance
static std::vector<char> print_buffer;
gpr buf = ctx->r5;
size_t size = ctx->r6;
//for (size_t i = 0; i < size; i++) {
// // Add the new character to the buffer
// char cur_char = MEM_B(i, buf);
// for (size_t i = 0; i < size; i++) {
// // Add the new character to the buffer
// char cur_char = MEM_B(i, buf);
// // If the new character is a newline, flush the buffer
// if (cur_char == '\n') {
@ -66,7 +67,7 @@ extern "C" void is_proutSyncPrintf_recomp(uint8_t * rdram, recomp_context * ctx)
// }
//}
//fwrite(to_print.get(), size, 1, stdout);
// fwrite(to_print.get(), size, 1, stdout);
ctx->r2 = 1;
}

View file

@ -1,22 +1,24 @@
#include <array>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <memory>
#include <cmath>
#include <unordered_map>
#include <unordered_set>
#include <fstream>
#include <iostream>
#include <optional>
#include <memory>
#include <mutex>
#include <array>
#include <optional>
#include <unordered_map>
#include <unordered_set>
#include "recomp.h"
#include "overlays.hpp"
#include "game.hpp"
#include "xxHash/xxh3.h"
#include "ultramodern/ultramodern.hpp"
#include "ultramodern/error_handling.hpp"
#include "ultramodern/ultramodern.hpp"
#include "game.hpp"
#include "overlays.hpp"
#include "recomp.h"
#ifdef _MSC_VER
inline uint32_t byteswap(uint32_t val) {
@ -40,7 +42,7 @@ std::mutex current_game_mutex;
// Global variables
std::filesystem::path config_path;
std::unordered_map<std::u8string, recomp::GameEntry> game_roms {};
std::unordered_map<std::u8string, recomp::GameEntry> game_roms{};
std::u8string recomp::GameEntry::stored_filename() const {
return game_id + u8".z64";
@ -64,14 +66,14 @@ bool check_hash(const std::vector<uint8_t>& rom_data, uint64_t expected_hash) {
static std::vector<uint8_t> read_file(const std::filesystem::path& path) {
std::vector<uint8_t> ret;
std::ifstream file{ path, std::ios::binary};
std::ifstream file{ path, std::ios::binary };
if (file.good()) {
file.seekg(0, std::ios::end);
ret.resize(file.tellg());
file.seekg(0, std::ios::beg);
file.read(reinterpret_cast<char*>(ret.data()), ret.size());
file.read(reinterpret_cast<char *>(ret.data()), ret.size());
}
return ret;
@ -84,7 +86,7 @@ bool write_file(const std::filesystem::path& path, const std::vector<uint8_t>& d
return false;
}
out_file.write(reinterpret_cast<const char*>(data.data()), data.size());
out_file.write(reinterpret_cast<const char *>(data.data()), data.size());
return true;
}
@ -108,7 +110,7 @@ bool recomp::is_rom_valid(std::u8string& game_id) {
}
void recomp::check_all_stored_roms() {
for (const auto& cur_rom_entry: game_roms) {
for (const auto& cur_rom_entry : game_roms) {
if (check_stored_rom(cur_rom_entry.second)) {
valid_game_roms.insert(cur_rom_entry.first);
}
@ -121,7 +123,7 @@ bool recomp::load_stored_rom(std::u8string& game_id) {
if (find_it == game_roms.end()) {
return false;
}
std::vector<uint8_t> stored_rom_data = read_file(config_path / find_it->second.stored_filename());
if (!check_hash(stored_rom_data, find_it->second.rom_hash)) {
@ -134,7 +136,7 @@ bool recomp::load_stored_rom(std::u8string& game_id) {
return true;
}
const std::array<uint8_t, 4> first_rom_bytes { 0x80, 0x37, 0x12, 0x40 };
const std::array<uint8_t, 4> first_rom_bytes{ 0x80, 0x37, 0x12, 0x40 };
enum class ByteswapType {
NotByteswapped,
@ -149,25 +151,22 @@ ByteswapType check_rom_start(const std::vector<uint8_t>& rom_data) {
}
auto check_match = [&](uint8_t index0, uint8_t index1, uint8_t index2, uint8_t index3) {
return
rom_data[0] == first_rom_bytes[index0] &&
rom_data[1] == first_rom_bytes[index1] &&
rom_data[2] == first_rom_bytes[index2] &&
rom_data[3] == first_rom_bytes[index3];
return rom_data[0] == first_rom_bytes[index0] && rom_data[1] == first_rom_bytes[index1] && rom_data[2] == first_rom_bytes[index2] &&
rom_data[3] == first_rom_bytes[index3];
};
// Check if the ROM is already in the correct byte order.
if (check_match(0,1,2,3)) {
if (check_match(0, 1, 2, 3)) {
return ByteswapType::NotByteswapped;
}
// Check if the ROM has been byteswapped in groups of 4 bytes.
if (check_match(3,2,1,0)) {
if (check_match(3, 2, 1, 0)) {
return ByteswapType::Byteswapped4;
}
// Check if the ROM has been byteswapped in groups of 2 bytes.
if (check_match(1,0,3,2)) {
if (check_match(1, 0, 3, 2)) {
return ByteswapType::Byteswapped2;
}
@ -223,12 +222,13 @@ recomp::RomValidationError recomp::select_rom(const std::filesystem::path& rom_p
}
if (!check_hash(rom_data, game_entry.rom_hash)) {
const std::string_view name{ reinterpret_cast<const char*>(rom_data.data()) + 0x20, game_entry.internal_name.size()};
const std::string_view name{ reinterpret_cast<const char *>(rom_data.data()) + 0x20, game_entry.internal_name.size() };
if (name == game_entry.internal_name) {
return recomp::RomValidationError::IncorrectVersion;
}
else {
if (game_entry.is_enabled && std::string_view{ reinterpret_cast<const char*>(rom_data.data()) + 0x20, 19 } == game_entry.internal_name) {
if (game_entry.is_enabled &&
std::string_view{ reinterpret_cast<const char *>(rom_data.data()) + 0x20, 19 } == game_entry.internal_name) {
return recomp::RomValidationError::NotYet;
}
else {
@ -238,11 +238,11 @@ recomp::RomValidationError recomp::select_rom(const std::filesystem::path& rom_p
}
write_file(config_path / game_entry.stored_filename(), rom_data);
return recomp::RomValidationError::Good;
}
extern "C" void osGetMemSize_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osGetMemSize_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = 8 * 1024 * 1024;
}
@ -250,7 +250,7 @@ enum class StatusReg {
FR = 0x04000000,
};
extern "C" void cop0_status_write(recomp_context* ctx, gpr value) {
extern "C" void cop0_status_write(recomp_context *ctx, gpr value) {
uint32_t old_sr = ctx->status_reg;
uint32_t new_sr = (uint32_t)value;
uint32_t changed = old_sr ^ new_sr;
@ -280,16 +280,16 @@ extern "C" void cop0_status_write(recomp_context* ctx, gpr value) {
assert(false);
exit(EXIT_FAILURE);
}
// Update the status register in the context
ctx->status_reg = new_sr;
}
extern "C" gpr cop0_status_read(recomp_context* ctx) {
extern "C" gpr cop0_status_read(recomp_context *ctx) {
return (gpr)(int32_t)ctx->status_reg;
}
extern "C" void switch_error(const char* func, uint32_t vram, uint32_t jtbl) {
extern "C" void switch_error(const char *func, uint32_t vram, uint32_t jtbl) {
printf("Switch-case out of bounds in %s at 0x%08X for jump table at 0x%08X\n", func, vram, jtbl);
assert(false);
exit(EXIT_FAILURE);
@ -301,17 +301,17 @@ extern "C" void do_break(uint32_t vram) {
exit(EXIT_FAILURE);
}
void run_thread_function(uint8_t* rdram, uint64_t addr, uint64_t sp, uint64_t arg) {
void run_thread_function(uint8_t *rdram, uint64_t addr, uint64_t sp, uint64_t arg) {
recomp_context ctx{};
ctx.r29 = sp;
ctx.r4 = arg;
ctx.mips3_float_mode = 0;
ctx.f_odd = &ctx.f0.u32h;
recomp_func_t* func = get_function(addr);
recomp_func_t *func = get_function(addr);
func(rdram, &ctx);
}
void init(uint8_t* rdram, recomp_context* ctx, gpr entrypoint) {
void init(uint8_t *rdram, recomp_context *ctx, gpr entrypoint) {
// Initialize the overlays
recomp::overlays::init_overlays();
@ -337,9 +337,9 @@ void init(uint8_t* rdram, recomp_context* ctx, gpr entrypoint) {
constexpr int32_t osVersion = 0x80000314;
constexpr int32_t osMemSize = 0x80000318;
constexpr int32_t osAppNMIBuffer = 0x8000031c;
MEM_W(osTvType, 0) = 1; // NTSC
MEM_W(osRomBase, 0) = 0xB0000000u; // standard rom base
MEM_W(osResetType, 0) = 0; // cold reset
MEM_W(osTvType, 0) = 1; // NTSC
MEM_W(osRomBase, 0) = 0xB0000000u; // standard rom base
MEM_W(osResetType, 0) = 0; // cold reset
MEM_W(osMemSize, 0) = 8 * 1024 * 1024; // 8MB
}
@ -374,25 +374,22 @@ void ultramodern::quit() {
}
void recomp::start(
ultramodern::renderer::WindowHandle window_handle,
const recomp::rsp::callbacks_t& rsp_callbacks,
const ultramodern::renderer::callbacks_t& renderer_callbacks,
const ultramodern::audio_callbacks_t& audio_callbacks,
const ultramodern::input::callbacks_t& input_callbacks,
const ultramodern::gfx_callbacks_t& gfx_callbacks_,
const ultramodern::events::callbacks_t& events_callbacks,
const ultramodern::error_handling::callbacks_t& error_handling_callbacks_
) {
ultramodern::renderer::WindowHandle window_handle, const recomp::rsp::callbacks_t& rsp_callbacks,
const ultramodern::renderer::callbacks_t& renderer_callbacks, const ultramodern::audio_callbacks_t& audio_callbacks,
const ultramodern::input::callbacks_t& input_callbacks, const ultramodern::gfx_callbacks_t& gfx_callbacks_,
const ultramodern::events::callbacks_t& events_callbacks, const ultramodern::error_handling::callbacks_t& error_handling_callbacks_) {
recomp::check_all_stored_roms();
recomp::rsp::set_callbacks(rsp_callbacks);
static const ultramodern::rsp::callbacks_t ultramodern_rsp_callbacks {
static const ultramodern::rsp::callbacks_t ultramodern_rsp_callbacks{
.init = recomp::rsp::constants_init,
.run_task = recomp::rsp::run_task,
};
ultramodern::set_callbacks(ultramodern_rsp_callbacks, renderer_callbacks, audio_callbacks, input_callbacks, gfx_callbacks_, events_callbacks, error_handling_callbacks_);
ultramodern::set_callbacks(
ultramodern_rsp_callbacks, renderer_callbacks, audio_callbacks, input_callbacks, gfx_callbacks_, events_callbacks,
error_handling_callbacks_);
ultramodern::gfx_callbacks_t gfx_callbacks = gfx_callbacks_;
@ -415,20 +412,20 @@ void recomp::start(
std::unique_ptr<uint8_t[]> rdram_buffer = std::make_unique<uint8_t[]>(ultramodern::rdram_size);
std::memset(rdram_buffer.get(), 0, ultramodern::rdram_size);
std::thread game_thread{[](ultramodern::renderer::WindowHandle window_handle, uint8_t* rdram) {
debug_printf("[Recomp] Starting\n");
std::thread game_thread{
[](ultramodern::renderer::WindowHandle window_handle, uint8_t *rdram) {
debug_printf("[Recomp] Starting\n");
ultramodern::set_native_thread_name("Game Start Thread");
ultramodern::set_native_thread_name("Game Start Thread");
ultramodern::preinit(rdram, window_handle);
ultramodern::preinit(rdram, window_handle);
game_status.wait(GameStatus::None);
recomp_context context{};
game_status.wait(GameStatus::None);
recomp_context context{};
switch (game_status.load()) {
// TODO refactor this to allow a project to specify what entrypoint function to run for a give game.
case GameStatus::Running:
{
switch (game_status.load()) {
// TODO refactor this to allow a project to specify what entrypoint function to run for a give game.
case GameStatus::Running: {
if (!recomp::load_stored_rom(current_game.value())) {
ultramodern::error_handling::message_box("Error opening stored ROM! Please restart this program.");
}
@ -443,20 +440,21 @@ void recomp::start(
try {
game_entry.entrypoint(rdram, &context);
} catch (ultramodern::thread_terminated& terminated) {
}
}
break;
} break;
case GameStatus::Quit:
break;
case GameStatus::Quit:
break;
case GameStatus::None:
break;
}
case GameStatus::None:
break;
}
debug_printf("[Recomp] Quitting\n");
}, window_handle, rdram_buffer.get()};
debug_printf("[Recomp] Quitting\n");
},
window_handle,
rdram_buffer.get(),
};
while (!exited) {
ultramodern::sleep_milliseconds(1);

View file

@ -1,10 +1,10 @@
#include <cassert>
#include <cstring>
#include <cinttypes>
#include <cstring>
#include "rsp.hpp"
static recomp::rsp::callbacks_t rsp_callbacks {};
static recomp::rsp::callbacks_t rsp_callbacks{};
void recomp::rsp::set_callbacks(const callbacks_t& callbacks) {
rsp_callbacks = callbacks;
@ -26,16 +26,17 @@ void recomp::rsp::constants_init() {
for (u16 index = 0; index < 512; index++) {
u64 a = (index + 512) >> ((index % 2 == 1) ? 1 : 0);
u64 b = 1 << 17;
//find the largest b where b < 1.0 / sqrt(a)
while (a * (b + 1) * (b + 1) < (u64(1) << 44)) b++;
// find the largest b where b < 1.0 / sqrt(a)
while (a * (b + 1) * (b + 1) < (u64(1) << 44))
b++;
rspInverseSquareRoots[index] = u16(b >> 1);
}
}
// Runs a recompiled RSP microcode
bool recomp::rsp::run_task(uint8_t* rdram, const OSTask* task) {
bool recomp::rsp::run_task(uint8_t *rdram, const OSTask *task) {
assert(rsp_callbacks.get_rsp_microcode != nullptr);
RspUcodeFunc* ucode_func = rsp_callbacks.get_rsp_microcode(task);
RspUcodeFunc *ucode_func = rsp_callbacks.get_rsp_microcode(task);
if (ucode_func == nullptr) {
fprintf(stderr, "No registered RSP ucode for %" PRIu32 " (returned `nullptr`)\n", task->t.type);

View file

@ -1,21 +1,24 @@
#include <cstdio>
#include <fstream>
#include <ultramodern/ultramodern.hpp>
#include "recomp.h"
extern "C" void osSpTaskLoad_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osSpTaskLoad_recomp(uint8_t *rdram, recomp_context *ctx) {
// Nothing to do here
}
bool dump_frame = false;
extern "C" void osSpTaskStartGo_recomp(uint8_t* rdram, recomp_context* ctx) {
//printf("[sp] osSpTaskStartGo(0x%08X)\n", (uint32_t)ctx->r4);
OSTask* task = TO_PTR(OSTask, ctx->r4);
extern "C" void osSpTaskStartGo_recomp(uint8_t *rdram, recomp_context *ctx) {
// printf("[sp] osSpTaskStartGo(0x%08X)\n", (uint32_t)ctx->r4);
OSTask *task = TO_PTR(OSTask, ctx->r4);
if (task->t.type == M_GFXTASK) {
//printf("[sp] Gfx task: %08X\n", (uint32_t)ctx->r4);
} else if (task->t.type == M_AUDTASK) {
//printf("[sp] Audio task: %08X\n", (uint32_t)ctx->r4);
// printf("[sp] Gfx task: %08X\n", (uint32_t)ctx->r4);
}
else if (task->t.type == M_AUDTASK) {
// printf("[sp] Audio task: %08X\n", (uint32_t)ctx->r4);
}
// For debugging
if (dump_frame) {
@ -24,7 +27,7 @@ extern "C" void osSpTaskStartGo_recomp(uint8_t* rdram, recomp_context* ctx) {
std::unique_ptr<char[]> ram_unswapped = std::make_unique<char[]>(ram_size);
snprintf(addr_str, sizeof(addr_str) - 1, "%08X", task->t.data_ptr);
addr_str[sizeof(addr_str) - 1] = '\0';
std::ofstream dump_file{ "ramdump" + std::string{ addr_str } + ".bin", std::ios::binary};
std::ofstream dump_file{ "ramdump" + std::string{ addr_str } + ".bin", std::ios::binary };
for (size_t i = 0; i < ram_size; i++) {
ram_unswapped[i] = rdram[i ^ 3];
@ -36,15 +39,15 @@ extern "C" void osSpTaskStartGo_recomp(uint8_t* rdram, recomp_context* ctx) {
ultramodern::submit_rsp_task(rdram, ctx->r4);
}
extern "C" void osSpTaskYield_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osSpTaskYield_recomp(uint8_t *rdram, recomp_context *ctx) {
// Ignore yield requests (acts as if the task completed before it received the yield request)
}
extern "C" void osSpTaskYielded_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osSpTaskYielded_recomp(uint8_t *rdram, recomp_context *ctx) {
// Task yield requests are ignored, so always return 0 as tasks will never be yielded
ctx->r2 = 0;
}
extern "C" void __osSpSetPc_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void __osSpSetPc_recomp(uint8_t *rdram, recomp_context *ctx) {
assert(false);
}

View file

@ -1,45 +1,45 @@
#include <ultramodern/ultra64.h>
#include <ultramodern/ultramodern.hpp>
#include "recomp.h"
// None of these functions need to be reimplemented, so stub them out
extern "C" void osUnmapTLBAll_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osUnmapTLBAll_recomp(uint8_t *rdram, recomp_context *ctx) {
// TODO this will need to be implemented in the future for any games that actually use the TLB
}
extern "C" void osVoiceInit_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osVoiceInit_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = 11; // CONT_ERR_DEVICE
}
extern "C" void osVoiceSetWord_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osVoiceSetWord_recomp(uint8_t *rdram, recomp_context *ctx) {
assert(false);
}
extern "C" void osVoiceCheckWord_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osVoiceCheckWord_recomp(uint8_t *rdram, recomp_context *ctx) {
assert(false);
}
extern "C" void osVoiceStopReadData_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osVoiceStopReadData_recomp(uint8_t *rdram, recomp_context *ctx) {
assert(false);
}
extern "C" void osVoiceMaskDictionary_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osVoiceMaskDictionary_recomp(uint8_t *rdram, recomp_context *ctx) {
assert(false);
}
extern "C" void osVoiceStartReadData_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osVoiceStartReadData_recomp(uint8_t *rdram, recomp_context *ctx) {
assert(false);
}
extern "C" void osVoiceControlGain_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osVoiceControlGain_recomp(uint8_t *rdram, recomp_context *ctx) {
assert(false);
}
extern "C" void osVoiceGetReadData_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osVoiceGetReadData_recomp(uint8_t *rdram, recomp_context *ctx) {
assert(false);
}
extern "C" void osVoiceClearDictionary_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osVoiceClearDictionary_recomp(uint8_t *rdram, recomp_context *ctx) {
assert(false);
}

View file

@ -1,132 +1,135 @@
#include <memory>
#include <ultramodern/ultra64.h>
#include <ultramodern/ultramodern.hpp>
#include "recomp.h"
extern "C" void osInitialize_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osInitialize_recomp(uint8_t *rdram, recomp_context *ctx) {
osInitialize();
}
extern "C" void __osInitialize_common_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void __osInitialize_common_recomp(uint8_t *rdram, recomp_context *ctx) {
osInitialize();
}
extern "C" void osCreateThread_recomp(uint8_t* rdram, recomp_context* ctx) {
osCreateThread(rdram, (int32_t)ctx->r4, (OSId)ctx->r5, (int32_t)ctx->r6, (int32_t)ctx->r7,
(int32_t)MEM_W(0x10, ctx->r29), (OSPri)MEM_W(0x14, ctx->r29));
extern "C" void osCreateThread_recomp(uint8_t *rdram, recomp_context *ctx) {
osCreateThread(
rdram, (int32_t)ctx->r4, (OSId)ctx->r5, (int32_t)ctx->r6, (int32_t)ctx->r7, (int32_t)MEM_W(0x10, ctx->r29),
(OSPri)MEM_W(0x14, ctx->r29));
}
extern "C" void osStartThread_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osStartThread_recomp(uint8_t *rdram, recomp_context *ctx) {
osStartThread(rdram, (int32_t)ctx->r4);
}
extern "C" void osStopThread_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osStopThread_recomp(uint8_t *rdram, recomp_context *ctx) {
osStopThread(rdram, (int32_t)ctx->r4);
}
extern "C" void osDestroyThread_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osDestroyThread_recomp(uint8_t *rdram, recomp_context *ctx) {
osDestroyThread(rdram, (int32_t)ctx->r4);
}
extern "C" void osYieldThread_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osYieldThread_recomp(uint8_t *rdram, recomp_context *ctx) {
assert(false);
// osYieldThread(rdram);
}
extern "C" void osSetThreadPri_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osSetThreadPri_recomp(uint8_t *rdram, recomp_context *ctx) {
osSetThreadPri(rdram, (int32_t)ctx->r4, (OSPri)ctx->r5);
}
extern "C" void osGetThreadPri_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osGetThreadPri_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = osGetThreadPri(rdram, (int32_t)ctx->r4);
}
extern "C" void osGetThreadId_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osGetThreadId_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = osGetThreadId(rdram, (int32_t)ctx->r4);
}
extern "C" void osCreateMesgQueue_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osCreateMesgQueue_recomp(uint8_t *rdram, recomp_context *ctx) {
osCreateMesgQueue(rdram, (int32_t)ctx->r4, (int32_t)ctx->r5, (s32)ctx->r6);
}
extern "C" void osRecvMesg_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osRecvMesg_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = osRecvMesg(rdram, (int32_t)ctx->r4, (int32_t)ctx->r5, (s32)ctx->r6);
}
extern "C" void osSendMesg_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osSendMesg_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = osSendMesg(rdram, (int32_t)ctx->r4, (OSMesg)ctx->r5, (s32)ctx->r6);
}
extern "C" void osJamMesg_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osJamMesg_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = osJamMesg(rdram, (int32_t)ctx->r4, (OSMesg)ctx->r5, (s32)ctx->r6);
}
extern "C" void osSetEventMesg_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osSetEventMesg_recomp(uint8_t *rdram, recomp_context *ctx) {
osSetEventMesg(rdram, (OSEvent)ctx->r4, (int32_t)ctx->r5, (OSMesg)ctx->r6);
}
extern "C" void osViSetEvent_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osViSetEvent_recomp(uint8_t *rdram, recomp_context *ctx) {
osViSetEvent(rdram, (int32_t)ctx->r4, (OSMesg)ctx->r5, (u32)ctx->r6);
}
extern "C" void osGetCount_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osGetCount_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = osGetCount();
}
extern "C" void osGetTime_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osGetTime_recomp(uint8_t *rdram, recomp_context *ctx) {
uint64_t total_count = osGetTime();
ctx->r2 = (int32_t)(total_count >> 32);
ctx->r3 = (int32_t)(total_count >> 0);
}
extern "C" void osSetTimer_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osSetTimer_recomp(uint8_t *rdram, recomp_context *ctx) {
uint64_t countdown = ((uint64_t)(ctx->r6) << 32) | ((ctx->r7) & 0xFFFFFFFFu);
uint64_t interval = load_doubleword(rdram, ctx->r29, 0x10);
ctx->r2 = osSetTimer(rdram, (int32_t)ctx->r4, countdown, interval, (int32_t)MEM_W(0x18, ctx->r29), (OSMesg)MEM_W(0x1C, ctx->r29));
}
extern "C" void osStopTimer_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osStopTimer_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = osStopTimer(rdram, (int32_t)ctx->r4);
}
extern "C" void osVirtualToPhysical_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osVirtualToPhysical_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = osVirtualToPhysical((int32_t)ctx->r4);
}
extern "C" void osInvalDCache_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osInvalDCache_recomp(uint8_t *rdram, recomp_context *ctx) {
;
}
extern "C" void osInvalICache_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osInvalICache_recomp(uint8_t *rdram, recomp_context *ctx) {
;
}
extern "C" void osWritebackDCache_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osWritebackDCache_recomp(uint8_t *rdram, recomp_context *ctx) {
;
}
extern "C" void osWritebackDCacheAll_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osWritebackDCacheAll_recomp(uint8_t *rdram, recomp_context *ctx) {
;
}
extern "C" void osSetIntMask_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void osSetIntMask_recomp(uint8_t *rdram, recomp_context *ctx) {
;
}
extern "C" void __osDisableInt_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void __osDisableInt_recomp(uint8_t *rdram, recomp_context *ctx) {
;
}
extern "C" void __osRestoreInt_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void __osRestoreInt_recomp(uint8_t *rdram, recomp_context *ctx) {
;
}
extern "C" void __osSetFpcCsr_recomp(uint8_t * rdram, recomp_context * ctx) {
extern "C" void __osSetFpcCsr_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = 0;
}
// For the Mario Party games (not working)
//extern "C" void longjmp_recomp(uint8_t * rdram, recomp_context * ctx) {
// extern "C" void longjmp_recomp(uint8_t * rdram, recomp_context * ctx) {
// RecompJmpBuf* buf = TO_PTR(RecompJmpBuf, ctx->r4);
//
// // Check if this is a buffer that was set up with setjmp
@ -153,11 +156,11 @@ extern "C" void __osSetFpcCsr_recomp(uint8_t * rdram, recomp_context * ctx) {
//}
//
//#undef setjmp_recomp
//extern "C" void setjmp_recomp(uint8_t * rdram, recomp_context * ctx) {
// extern "C" void setjmp_recomp(uint8_t * rdram, recomp_context * ctx) {
// fprintf(stderr, "Program called setjmp_recomp\n");
// std::quick_exit(EXIT_FAILURE);
//}
//
//extern "C" int32_t osGetThreadEx(void) {
// extern "C" int32_t osGetThreadEx(void) {
// return ultramodern::this_thread();
//}

View file

@ -1,45 +1,46 @@
#include <ultramodern/ultramodern.hpp>
#include "recomp.h"
extern "C" void osViSetYScale_recomp(uint8_t* rdram, recomp_context * ctx) {
extern "C" void osViSetYScale_recomp(uint8_t *rdram, recomp_context *ctx) {
osViSetYScale(ctx->f12.fl);
}
extern "C" void osViSetXScale_recomp(uint8_t* rdram, recomp_context * ctx) {
extern "C" void osViSetXScale_recomp(uint8_t *rdram, recomp_context *ctx) {
osViSetXScale(ctx->f12.fl);
}
extern "C" void osCreateViManager_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osCreateViManager_recomp(uint8_t *rdram, recomp_context *ctx) {
;
}
extern "C" void osViBlack_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osViBlack_recomp(uint8_t *rdram, recomp_context *ctx) {
osViBlack((uint32_t)ctx->r4);
}
extern "C" void osViSetSpecialFeatures_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osViSetSpecialFeatures_recomp(uint8_t *rdram, recomp_context *ctx) {
osViSetSpecialFeatures((uint32_t)ctx->r4);
}
extern "C" void osViGetCurrentFramebuffer_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osViGetCurrentFramebuffer_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = (gpr)(int32_t)osViGetCurrentFramebuffer();
}
extern "C" void osViGetNextFramebuffer_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osViGetNextFramebuffer_recomp(uint8_t *rdram, recomp_context *ctx) {
ctx->r2 = (gpr)(int32_t)osViGetNextFramebuffer();
}
extern "C" void osViSwapBuffer_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osViSwapBuffer_recomp(uint8_t *rdram, recomp_context *ctx) {
osViSwapBuffer(rdram, (int32_t)ctx->r4);
}
extern "C" void osViSetMode_recomp(uint8_t* rdram, recomp_context* ctx) {
extern "C" void osViSetMode_recomp(uint8_t *rdram, recomp_context *ctx) {
osViSetMode(rdram, (int32_t)ctx->r4);
}
extern uint64_t total_vis;
extern "C" void wait_one_frame(uint8_t* rdram, recomp_context* ctx) {
extern "C" void wait_one_frame(uint8_t *rdram, recomp_context *ctx) {
uint64_t cur_vis = total_vis;
while (cur_vis == total_vis) {
std::this_thread::yield();