Added recomp runtime library and portultra, MM initial boot

This commit is contained in:
Mr-Wiseguy
2023-02-19 22:27:35 -05:00
parent 7847975e57
commit ba37150ed1
46 changed files with 29616 additions and 27 deletions
+29
View File
@@ -0,0 +1,29 @@
#include "recomp.h"
#include <cstdio>
#include <string>
#include "../portultra/ultra64.h"
#include "../portultra/multilibultra.hpp"
#define VI_NTSC_CLOCK 48681812
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;
ctx->r2 = freq;
Multilibultra::set_audio_frequency(freq);
}
extern "C" void osAiSetNextBuffer_recomp(uint8_t* rdram, recomp_context* ctx) {
Multilibultra::queue_audio_buffer(rdram, ctx->r4, ctx->r5);
ctx->r2 = 0;
}
extern "C" void osAiGetLength_recomp(uint8_t* rdram, recomp_context* ctx) {
ctx->r2 = Multilibultra::get_remaining_audio_bytes();
}
extern "C" void osAiGetStatus_recomp(uint8_t* rdram, recomp_context* ctx) {
ctx->r2 = 0x00000000; // Pretend the audio DMAs finish instantly
}
+108
View File
@@ -0,0 +1,108 @@
#include "../portultra/multilibultra.hpp"
#include "recomp.h"
static int max_controllers = 0;
extern "C" void osContInit_recomp(uint8_t* rdram, recomp_context* ctx) {
gpr bitpattern = ctx->r5;
gpr status = ctx->r6;
// Set bit 0 to indicate that controller 0 is present
MEM_B(0, bitpattern) = 0x01;
// Mark controller 0 as present
MEM_H(0, status) = 0x0005; // type: CONT_TYPE_NORMAL (from joybus)
MEM_B(2, status) = 0x00; // status: 0 (from joybus)
MEM_B(3, status) = 0x00; // errno: 0 (from libultra)
max_controllers = 4;
// Mark controllers 1-3 as not connected
for (size_t controller = 1; controller < max_controllers; controller++) {
// Libultra doesn't write status or type for absent controllers
MEM_B(4 * controller + 3, status) = 0x80 >> 4; // errno: CONT_NO_RESPONSE_ERROR >> 4
}
ctx->r2 = 0;
}
extern "C" void osContStartReadData_recomp(uint8_t* rdram, recomp_context* ctx) {
Multilibultra::send_si_message();
}
struct OSContPad {
u16 button;
s8 stick_x; /* -80 <= stick_x <= 80 */
s8 stick_y; /* -80 <= stick_y <= 80 */
u8 errno_;
};
int button = 0;
int stick_x = 0;
int stick_y = 0;
void press_button(int button) {
}
void release_button(int button) {
}
extern "C" void osContGetReadData_recomp(uint8_t* rdram, recomp_context* ctx) {
int32_t pad = (int32_t)ctx->r4;
if (max_controllers > 0) {
// button
MEM_H(0, pad) = button;
// stick_x
MEM_B(2, pad) = stick_x;
// stick_y
MEM_B(3, pad) = stick_y;
// errno
MEM_B(4, pad) = 0;
}
for (int controller = 1; controller < max_controllers; controller++) {
MEM_B(6 * controller + 4, pad) = 0x80 >> 4; // errno: CONT_NO_RESPONSE_ERROR >> 4
}
}
extern "C" void osContStartQuery_recomp(uint8_t * rdram, recomp_context * ctx) {
Multilibultra::send_si_message();
}
extern "C" void osContGetQuery_recomp(uint8_t * rdram, recomp_context * ctx) {
gpr status = ctx->r4;
// Mark controller 0 as present
MEM_H(0, status) = 0x0005; // type: CONT_TYPE_NORMAL (from joybus)
MEM_B(2, status) = 0x00; // status: 0 (from joybus)
MEM_B(3, status) = 0x00; // errno: 0 (from libultra)
// Mark controllers 1-3 as not connected
for (size_t controller = 1; controller < max_controllers; controller++) {
// Libultra doesn't write status or type for absent controllers
MEM_B(4 * controller + 3, status) = 0x80 >> 4; // errno: CONT_NO_RESPONSE_ERROR >> 4
}
}
extern "C" void osContSetCh_recomp(uint8_t* rdram, recomp_context* ctx) {
max_controllers = std::min((unsigned int)ctx->r4, 4u);
ctx->r2 = 0;
}
extern "C" void __osMotorAccess_recomp(uint8_t* rdram, recomp_context* ctx) {
}
extern "C" void osMotorInit_recomp(uint8_t* rdram, recomp_context* ctx) {
;
}
extern "C" void osMotorStart_recomp(uint8_t* rdram, recomp_context* ctx) {
;
}
extern "C" void osMotorStop_recomp(uint8_t* rdram, recomp_context* ctx) {
;
}
+5
View File
@@ -0,0 +1,5 @@
#include "recomp.h"
extern "C" void osDpSetNextBuffer_recomp(uint8_t* rdram, recomp_context* ctx) {
;
}
+21
View File
@@ -0,0 +1,21 @@
#include "recomp.h"
extern "C" void osEepromProbe_recomp(uint8_t* rdram, recomp_context* ctx) {
;
}
extern "C" void osEepromWrite_recomp(uint8_t* rdram, recomp_context* ctx) {
;
}
extern "C" void osEepromLongWrite_recomp(uint8_t* rdram, recomp_context* ctx) {
;
}
extern "C" void osEepromRead_recomp(uint8_t* rdram, recomp_context* ctx) {
;
}
extern "C" void osEepromLongRead_recomp(uint8_t* rdram, recomp_context* ctx) {
;
}
+2587
View File
File diff suppressed because it is too large Load Diff
+11
View File
@@ -0,0 +1,11 @@
#ifndef __EUC_JP_H__
#define __EUC_JP_H__
#include <string>
#include <string_view>
namespace Encoding {
std::string decode_eucjp(std::string_view src);
}
#endif
+137
View File
@@ -0,0 +1,137 @@
#include <array>
#include <cassert>
#include "../portultra/ultra64.h"
#include "../portultra/multilibultra.hpp"
#include "recomp.h"
constexpr uint32_t flash_size = 1024 * 1024 / 8; // 1Mbit
constexpr uint32_t page_size = 128;
constexpr uint32_t pages_per_sector = 128;
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(uint8_t* rdram, gpr rdram_address, uint32_t offset, uint32_t count);
void save_read(uint8_t* rdram, gpr rdram_address, uint32_t offset, uint32_t count);
void save_clear(uint32_t start, uint32_t size);
std::array<char, page_size> write_buffer;
extern "C" void osFlashInit_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = Multilibultra::flash_handle;
}
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) {
PTR(u32) flash_type = ctx->r4;
PTR(u32) flash_maker = ctx->r5;
MEM_B(0, flash_type) = 0;
MEM_B(0, flash_maker) = 0;
}
extern "C" void osFlashClearStatus_recomp(uint8_t * rdram, recomp_context * ctx) {
}
extern "C" void osFlashAllErase_recomp(uint8_t * rdram, recomp_context * ctx) {
save_clear(0, Multilibultra::save_size);
ctx->r2 = 0;
}
extern "C" void osFlashAllEraseThrough_recomp(uint8_t * rdram, recomp_context * ctx) {
save_clear(0, Multilibultra::save_size);
ctx->r2 = 0;
}
extern "C" void osFlashSectorErase_recomp(uint8_t * rdram, recomp_context * ctx) {
uint32_t page_num = (uint32_t)ctx->r4;
uint32_t sector_num = page_num / sector_size;
// Prevent out of bounds erase
if (sector_num >= sector_size) {
ctx->r2 = -1;
return;
}
save_clear(sector_num * sector_size, sector_size);
ctx->r2 = 0;
}
extern "C" void osFlashSectorEraseThrough_recomp(uint8_t * rdram, recomp_context * ctx) {
uint32_t page_num = (uint32_t)ctx->r4;
uint32_t sector_num = page_num / sector_size;
// Prevent out of bounds erase
if (sector_num >= sector_size) {
ctx->r2 = -1;
return;
}
save_clear(sector_num * sector_size, sector_size);
ctx->r2 = 0;
}
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);
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);
}
// Send the message indicating write completion
osSendMesg(PASS_RDRAM mq, 0, OS_MESG_NOBLOCK);
ctx->r2 = 0;
}
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
save_write_ptr(write_buffer.data(), page_num * page_size, page_size);
ctx->r2 = 0;
}
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;
uint32_t n_pages = MEM_W(0x10, ctx->r29);
PTR(OSMesgQueue) mq = MEM_W(0x14, ctx->r29);
uint32_t offset = page_num * page_size;
uint32_t count = n_pages * page_size;
// Read from the save file into the provided buffer
save_read(PASS_RDRAM dramAddr, offset, count);
// Send the message indicating read completion
osSendMesg(PASS_RDRAM mq, 0, OS_MESG_NOBLOCK);
ctx->r2 = 0;
}
extern "C" void osFlashChange_recomp(uint8_t * rdram, recomp_context * ctx) {
assert(false);
}
+80
View File
@@ -0,0 +1,80 @@
#include "../portultra/multilibultra.hpp"
#include "recomp.h"
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;
ctx->r2 = (int32_t)(ret >> 32);
ctx->r3 = (int32_t)(ret >> 0);
}
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;
ctx->r2 = (int32_t)(ret >> 32);
ctx->r3 = (int32_t)(ret >> 0);
}
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;
ctx->r2 = (int32_t)(ret >> 32);
ctx->r3 = (int32_t)(ret >> 0);
}
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;
ctx->r2 = (int32_t)(ret >> 32);
ctx->r3 = (int32_t)(ret >> 0);
}
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;
ctx->r2 = (int32_t)(ret >> 32);
ctx->r3 = (int32_t)(ret >> 0);
}
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;
ctx->r2 = (int32_t)(ret >> 32);
ctx->r3 = (int32_t)(ret >> 0);
}
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;
ctx->r2 = (int32_t)(ret >> 32);
ctx->r3 = (int32_t)(ret >> 0);
}
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) {
uint64_t a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu);
float ret = (float)a;
ctx->f0.fl = ret;
}
+110
View File
@@ -0,0 +1,110 @@
#include <unordered_map>
#include <algorithm>
#include <vector>
#include "recomp.h"
#include "../RecompiledFuncs/recomp_overlays.inl"
constexpr size_t num_code_sections = ARRLEN(section_table);
// SectionTableEntry sections[] defined in recomp_overlays.inl
struct LoadedSection {
int32_t loaded_ram_addr;
size_t section_table_index;
bool operator<(const LoadedSection& rhs) {
return loaded_ram_addr < rhs.loaded_ram_addr;
}
};
std::vector<LoadedSection> loaded_sections{};
std::unordered_map<int32_t, recomp_func_t*> func_map{};
void load_overlay(size_t section_table_index, int32_t ram) {
const SectionTableEntry& section = section_table[section_table_index];
for (size_t function_index = 0; function_index < section.num_funcs; function_index++) {
const FuncEntry& func = section.funcs[function_index];
func_map[ram + func.offset] = func.func;
}
loaded_sections.emplace_back(ram, section_table_index);
section_addresses[section.index] = ram;
}
extern "C" {
int32_t section_addresses[num_sections];
}
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(&section_table[0], &section_table[num_code_sections], rom,
[](const SectionTableEntry& entry, uint32_t addr) {
return entry.rom_addr < addr;
}
);
auto upper = std::upper_bound(&section_table[0], &section_table[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(&section_table[0], it), it->rom_addr - rom + ram_addr);
}
}
extern "C" void unload_overlays(int32_t ram_addr, uint32_t size) {
for (auto it = loaded_sections.begin(); it != loaded_sections.end();) {
const auto& section = section_table[it->section_table_index];
// Check if the unloaded region overlaps with the loaded section
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,
"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);
std::exit(EXIT_FAILURE);
}
// Determine where each function was loaded to and remove that entry from the function map
for (size_t func_index = 0; func_index < section.num_funcs; func_index++) {
const auto& func = section.funcs[func_index];
uint32_t func_address = func.offset + it->loaded_ram_addr;
func_map.erase(func_address);
}
// Reset the section's address in the address table
section_addresses[section.index] = 0;
// Remove the section from the loaded section map
it = loaded_sections.erase(it);
// Skip incrementing the iterator
continue;
}
++it;
}
}
void init_overlays() {
for (size_t section_index = 0; section_index < num_code_sections; section_index++) {
section_addresses[section_table[section_index].index] = section_table[section_index].ram_addr;
}
// Sort the executable sections by rom address
std::sort(&section_table[0], &section_table[num_code_sections],
[](const SectionTableEntry& a, const SectionTableEntry& b) {
return a.rom_addr < b.rom_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);
std::exit(EXIT_FAILURE);
}
return func_find->second;
}
+31
View File
@@ -0,0 +1,31 @@
#include "recomp.h"
#include "../portultra/ultra64.h"
#include "../portultra/multilibultra.hpp"
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) {
ctx->r2 = 1; // PFS_ERR_NOPACK
}
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) {
ctx->r2 = 1; // PFS_ERR_NOPACK
}
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) {
ctx->r2 = 1; // PFS_ERR_NOPACK
}
extern "C" void osPfsReadWriteFile_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK
}
+193
View File
@@ -0,0 +1,193 @@
#include <memory>
#include <fstream>
#include <array>
#include "recomp.h"
#include "../portultra/ultra64.h"
#include "../portultra/multilibultra.hpp"
// Flashram occupies the same physical address as sram, but that issue is avoided because libultra exposes
// a high-level interface for flashram. Because that high-level interface is reimplemented, low level accesses
// that involve physical addresses don't need to be handled for flashram.
constexpr uint32_t sram_base = 0x08000000;
constexpr uint32_t rom_base = 0x10000000;
constexpr uint32_t k1_to_phys(uint32_t addr) {
return addr & 0x1FFFFFFF;
}
constexpr uint32_t phys_to_k1(uint32_t addr) {
return addr | 0xA0000000;
}
extern std::unique_ptr<uint8_t[]> rom;
extern size_t rom_size;
extern "C" void osCartRomInit_recomp(uint8_t* rdram, recomp_context* ctx) {
OSPiHandle* handle = TO_PTR(OSPiHandle, Multilibultra::cart_handle);
handle->type = 0; // cart
handle->baseAddress = phys_to_k1(rom_base);
handle->domain = 0;
ctx->r2 = (gpr)Multilibultra::cart_handle;
}
extern "C" void osCreatePiManager_recomp(uint8_t* rdram, recomp_context* ctx) {
;
}
void do_rom_read(uint8_t* rdram, gpr ram_address, uint32_t physical_addr, size_t num_bytes) {
// TODO use word copies when possible
uint8_t* rom_addr = rom.get() + physical_addr - rom_base;
for (size_t i = 0; i < num_bytes; i++) {
MEM_B(i, ram_address) = *rom_addr;
rom_addr++;
}
}
std::array<char, 0x20000> save_buffer;
const char save_filename[] = "save.bin";
void update_save_file() {
std::ofstream save_file{ save_filename, std::ios_base::binary };
if (save_file.good()) {
save_file.write(save_buffer.data(), save_buffer.size());
} else {
fprintf(stderr, "Failed to save!\n");
std::exit(EXIT_FAILURE);
}
}
void save_write_ptr(const void* in, uint32_t offset, uint32_t count) {
memcpy(&save_buffer[offset], in, count);
update_save_file();
}
void save_write(uint8_t* rdram, gpr rdram_address, uint32_t offset, uint32_t count) {
for (uint32_t i = 0; i < count; i++) {
save_buffer[offset + i] = MEM_B(i, rdram_address);
}
update_save_file();
}
void save_read(uint8_t* rdram, gpr rdram_address, uint32_t offset, uint32_t count) {
for (size_t i = 0; i < count; i++) {
MEM_B(i, rdram_address) = save_buffer[offset + i];
}
}
void save_clear(uint32_t start, uint32_t size) {
std::fill_n(save_buffer.begin() + start, size, 0);
std::ofstream save_file{ save_filename, std::ios_base::binary };
if (save_file.good()) {
save_file.write(save_buffer.data(), save_buffer.size());
} else {
fprintf(stderr, "Failed to save!\n");
std::exit(EXIT_FAILURE);
}
}
void Multilibultra::save_init() {
std::ifstream save_file{ save_filename, std::ios_base::binary };
if (save_file.good()) {
save_file.read(save_buffer.data(), save_buffer.size());
} else {
save_buffer.fill(0);
}
}
void do_dma(uint8_t* rdram, PTR(OSMesgQueue) mq, gpr rdram_address, uint32_t physical_addr, uint32_t size, uint32_t direction) {
// TODO asynchronous transfer
// TODO implement unaligned DMA correctly
if (direction == 0) {
if (physical_addr >= rom_base) {
// read cart rom
do_rom_read(rdram, rdram_address, physical_addr, size);
// 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) {
// 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 {
fprintf(stderr, "[WARN] PI DMA read from unknown region, phys address 0x%08X\n", physical_addr);
}
} else {
if (physical_addr >= rom_base) {
// write cart rom
throw std::runtime_error("ROM DMA write unimplemented");
} 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 {
fprintf(stderr, "[WARN] PI DMA write to unknown region, phys address 0x%08X\n", physical_addr);
}
}
}
extern "C" void osPiStartDma_recomp(uint8_t* rdram, recomp_context* ctx) {
uint32_t mb = ctx->r4;
uint32_t pri = ctx->r5;
uint32_t direction = ctx->r6;
uint32_t devAddr = ctx->r7;
gpr dramAddr = MEM_W(0x10, ctx->r29);
uint32_t size = MEM_W(0x14, ctx->r29);
PTR(OSMesgQueue) mq = MEM_W(0x18, ctx->r29);
uint32_t physical_addr = k1_to_phys(devAddr);
debug_printf("[pi] DMA from 0x%08X into 0x%08X of size 0x%08X\n", devAddr, dramAddr, size);
do_dma(rdram, mq, dramAddr, physical_addr, size, direction);
ctx->r2 = 0;
}
extern "C" void osEPiStartDma_recomp(uint8_t* rdram, 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;
uint32_t size = mb->size;
PTR(OSMesgQueue) mq = mb->hdr.retQueue;
uint32_t physical_addr = k1_to_phys(devAddr);
debug_printf("[pi] DMA from 0x%08X into 0x%08X of size 0x%08X\n", devAddr, dramAddr, size);
do_dma(rdram, mq, dramAddr, physical_addr, size, direction);
ctx->r2 = 0;
}
extern "C" void osEPiReadIo_recomp(uint8_t * rdram, 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);
if (physical_addr > rom_base) {
// cart rom
do_rom_read(rdram, dramAddr, physical_addr, sizeof(uint32_t));
} else {
// sram
assert(false && "SRAM ReadIo unimplemented");
}
ctx->r2 = 0;
}
extern "C" void osPiGetStatus_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = 0;
}
extern "C" void osPiRawStartDma_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = 0;
}
+45
View File
@@ -0,0 +1,45 @@
#include "../portultra/ultra64.h"
#include "../portultra/multilibultra.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) {
// 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) {
ctx->r2 = 11; // CONT_ERR_DEVICE
}
extern "C" void osVoiceSetWord_recomp(uint8_t * rdram, recomp_context * ctx) {
assert(false);
}
extern "C" void osVoiceCheckWord_recomp(uint8_t * rdram, recomp_context * ctx) {
assert(false);
}
extern "C" void osVoiceStopReadData_recomp(uint8_t * rdram, recomp_context * ctx) {
assert(false);
}
extern "C" void osVoiceMaskDictionary_recomp(uint8_t * rdram, recomp_context * ctx) {
assert(false);
}
extern "C" void osVoiceStartReadData_recomp(uint8_t * rdram, recomp_context * ctx) {
assert(false);
}
extern "C" void osVoiceControlGain_recomp(uint8_t * rdram, recomp_context * ctx) {
assert(false);
}
extern "C" void osVoiceGetReadData_recomp(uint8_t * rdram, recomp_context * ctx) {
assert(false);
}
extern "C" void osVoiceClearDictionary_recomp(uint8_t * rdram, recomp_context * ctx) {
assert(false);
}
+158
View File
@@ -0,0 +1,158 @@
#include <memory>
#include "../portultra/ultra64.h"
#include "../portultra/multilibultra.hpp"
#include "recomp.h"
extern "C" void osInitialize_recomp(uint8_t * rdram, recomp_context * ctx) {
osInitialize();
}
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 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) {
osStopThread(rdram, (int32_t)ctx->r4);
}
extern "C" void osDestroyThread_recomp(uint8_t * rdram, recomp_context * ctx) {
osDestroyThread(rdram, (int32_t)ctx->r4);
}
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) {
ctx->r2 = osGetThreadPri(rdram, (int32_t)ctx->r4);
}
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) {
osCreateMesgQueue(rdram, (int32_t)ctx->r4, (int32_t)ctx->r5, (s32)ctx->r6);
}
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) {
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) {
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) {
osSetEventMesg(rdram, (OSEvent)ctx->r4, (int32_t)ctx->r5, (OSMesg)ctx->r6);
}
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) {
ctx->r2 = osGetCount();
}
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) {
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) {
ctx->r2 = osStopTimer(rdram, (int32_t)ctx->r4);
}
extern "C" void osVirtualToPhysical_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = osVirtualToPhysical((int32_t)ctx->r2);
}
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 osWritebackDCache_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 __osDisableInt_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) {
ctx->r2 = 0;
}
// For the Mario Party games (not working)
//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
// if (buf->magic == SETJMP_MAGIC) {
// // If so, longjmp to it
// // Setjmp/longjmp does not work across threads, so verify that this buffer was made by this thread
// assert(buf->owner == Multilibultra::this_thread());
// longjmp(buf->storage->buffer, ctx->r5);
// } else {
// // Otherwise, check if it was one built manually by the game with $ra pointing to a function
// gpr sp = MEM_W(0, ctx->r4);
// gpr ra = MEM_W(4, ctx->r4);
// ctx->r29 = sp;
// recomp_func_t* target = LOOKUP_FUNC(ra);
// if (target == nullptr) {
// fprintf(stderr, "Failed to find function for manual longjmp\n");
// std::quick_exit(EXIT_FAILURE);
// }
// target(rdram, ctx);
//
// // TODO kill this thread if the target function returns
// assert(false);
// }
//}
//
//#undef setjmp_recomp
//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) {
// return Multilibultra::this_thread();
//}
+70
View File
@@ -0,0 +1,70 @@
#include "../portultra/ultra64.h"
#include "../portultra/multilibultra.hpp"
#include "recomp.h"
#include "euc-jp.h"
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) {
ctx->r2 = 0;
}
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_kmc_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 __osRdbSend_recomp(uint8_t * rdram, recomp_context * ctx) {
gpr buf = ctx->r4;
size_t size = ctx->r5;
u32 type = (u32)ctx->r6;
std::unique_ptr<char[]> to_print = std::make_unique<char[]>(size + 1);
for (size_t i = 0; i < size; i++) {
to_print[i] = MEM_B(i, buf);
}
to_print[size] = '\x00';
fwrite(to_print.get(), 1, size, stdout);
ctx->r2 = size;
}
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);
// // If the new character is a newline, flush the buffer
// if (cur_char == '\n') {
// std::string utf8_str = Encoding::decode_eucjp(std::string_view{ print_buffer.data(), print_buffer.size() });
// puts(utf8_str.c_str());
// print_buffer.clear();
// } else {
// print_buffer.push_back(cur_char);
// }
//}
//fwrite(to_print.get(), size, 1, stdout);
ctx->r2 = 1;
}
+165
View File
@@ -0,0 +1,165 @@
#ifdef _WIN32
#include <Windows.h>
#endif
#include <cstdio>
#include <cstdlib>
#include <memory>
#include <cmath>
#include <unordered_map>
#include <fstream>
#include <iostream>
#include "recomp.h"
#include "../portultra/multilibultra.hpp"
#ifdef _MSC_VER
inline uint32_t byteswap(uint32_t val) {
return _byteswap_ulong(val);
}
#else
constexpr uint32_t byteswap(uint32_t val) {
return __builtin_bswap32(val);
}
#endif
extern "C" void _bzero(uint8_t* rdram, recomp_context* ctx) {
gpr start_addr = ctx->r4;
gpr size = ctx->r5;
for (uint32_t i = 0; i < size; i++) {
MEM_B(start_addr, i) = 0;
}
}
extern "C" void osGetMemSize_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = 8 * 1024 * 1024;
}
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);
exit(EXIT_FAILURE);
}
extern "C" void do_break(uint32_t vram) {
printf("Encountered break at original vram 0x%08X\n", vram);
exit(EXIT_FAILURE);
}
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;
recomp_func_t* func = get_function(addr);
func(rdram, &ctx);
}
void do_rom_read(uint8_t* rdram, gpr ram_address, uint32_t dev_address, size_t num_bytes);
std::unique_ptr<uint8_t[]> rom;
size_t rom_size;
// Recomp generation functions
extern "C" void recomp_entrypoint(uint8_t * rdram, recomp_context * ctx);
gpr get_entrypoint_address();
const char* get_rom_name();
void init_overlays();
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);
#ifdef _WIN32
#include <Windows.h>
#endif
int main(int argc, char **argv) {
//if (argc != 2) {
// printf("Usage: %s [baserom]\n", argv[0]);
// exit(EXIT_SUCCESS);
//}
#ifdef _WIN32
// Set up console output to accept UTF-8 on windows
SetConsoleOutputCP(CP_UTF8);
// Change to a font that supports Japanese characters
CONSOLE_FONT_INFOEX cfi;
cfi.cbSize = sizeof cfi;
cfi.nFont = 0;
cfi.dwFontSize.X = 0;
cfi.dwFontSize.Y = 16;
cfi.FontFamily = FF_DONTCARE;
cfi.FontWeight = FW_NORMAL;
wcscpy_s(cfi.FaceName, L"NSimSun");
SetCurrentConsoleFontEx(GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &cfi);
#else
std::setlocale(LC_ALL, "en_US.UTF-8");
#endif
{
std::basic_ifstream<uint8_t> rom_file{ get_rom_name(), std::ios::binary };
size_t iobuf_size = 0x100000;
std::unique_ptr<uint8_t[]> iobuf = std::make_unique<uint8_t[]>(iobuf_size);
rom_file.rdbuf()->pubsetbuf(iobuf.get(), iobuf_size);
if (!rom_file) {
fprintf(stderr, "Failed to open rom: %s\n", get_rom_name());
exit(EXIT_FAILURE);
}
rom_file.seekg(0, std::ios::end);
rom_size = rom_file.tellg();
rom_file.seekg(0, std::ios::beg);
rom = std::make_unique<uint8_t[]>(rom_size);
rom_file.read(rom.get(), rom_size);
// TODO remove this
// Modify the name in the rom header so RT64 doesn't find it
rom[0x2F] = 'O';
}
// Initialize the overlays
init_overlays();
// Get entrypoint from recomp function
gpr entrypoint = get_entrypoint_address();
// Load overlays in the first 1MB
load_overlays(0x1000, (int32_t)entrypoint, 1024 * 1024);
// Allocate rdram_buffer (16MB to give room for any extra addressable data used by recomp)
std::unique_ptr<uint8_t[]> rdram_buffer = std::make_unique<uint8_t[]>(16 * 1024 * 1024);
std::memset(rdram_buffer.get(), 0, 8 * 1024 * 1024);
recomp_context context{};
// Initial 1MB DMA (rom address 0x1000 = physical address 0x10001000)
do_rom_read(rdram_buffer.get(), entrypoint, 0x10001000, 0x100000);
// Set up stack pointer
context.r29 = 0xFFFFFFFF803FFFF0u;
// Initialize variables normally set by IPL3
constexpr int32_t osTvType = 0x80000300;
constexpr int32_t osRomType = 0x80000304;
constexpr int32_t osRomBase = 0x80000308;
constexpr int32_t osResetType = 0x8000030c;
constexpr int32_t osCicId = 0x80000310;
constexpr int32_t osVersion = 0x80000314;
constexpr int32_t osMemSize = 0x80000318;
constexpr int32_t osAppNMIBuffer = 0x8000031c;
uint8_t *rdram = rdram_buffer.get();
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
debug_printf("[Recomp] Starting\n");
Multilibultra::preinit(rdram_buffer.get(), rom.get());
recomp_entrypoint(rdram_buffer.get(), &context);
debug_printf("[Recomp] Quitting\n");
return EXIT_SUCCESS;
}
+114
View File
@@ -0,0 +1,114 @@
#include <memory>
#include <Windows.h>
#include "../portultra/multilibultra.hpp"
#include "rt64_layer.h"
#include "SDL.h"
static uint8_t DMEM[0x1000];
static uint8_t IMEM[0x1000];
unsigned int MI_INTR_REG = 0;
unsigned int DPC_START_REG = 0;
unsigned int DPC_END_REG = 0;
unsigned int DPC_CURRENT_REG = 0;
unsigned int DPC_STATUS_REG = 0;
unsigned int DPC_CLOCK_REG = 0;
unsigned int DPC_BUFBUSY_REG = 0;
unsigned int DPC_PIPEBUSY_REG = 0;
unsigned int DPC_TMEM_REG = 0;
unsigned int VI_STATUS_REG = 0;
unsigned int VI_ORIGIN_REG = 0;
unsigned int VI_WIDTH_REG = 0;
unsigned int VI_INTR_REG = 0;
unsigned int VI_V_CURRENT_LINE_REG = 0;
unsigned int VI_TIMING_REG = 0;
unsigned int VI_V_SYNC_REG = 0;
unsigned int VI_H_SYNC_REG = 0;
unsigned int VI_LEAP_REG = 0;
unsigned int VI_H_START_REG = 0;
unsigned int VI_V_START_REG = 0;
unsigned int VI_V_BURST_REG = 0;
unsigned int VI_X_SCALE_REG = 0;
unsigned int VI_Y_SCALE_REG = 0;
unsigned int SP_STATUS_REG = 0;
unsigned int RDRAM_SIZE = 0x800000;
#define GET_FUNC(lib, name) \
name = (decltype(name))GetProcAddress(lib, #name)
void dummy_check_interrupts() {
}
void RT64Init(uint8_t* rom, uint8_t* rdram) {
// Dynamic loading
//auto RT64 = LoadLibrary("RT64.dll");
//if (RT64 == 0) {
// fprintf(stdout, "Failed to load RT64\n");
// std::exit(EXIT_FAILURE);
//}
//GET_FUNC(RT64, InitiateGFX);
//GET_FUNC(RT64, ProcessRDPList);
//GET_FUNC(RT64, ProcessDList);
//GET_FUNC(RT64, UpdateScreen);
GFX_INFO gfx_info{};
gfx_info.HEADER = rom;
gfx_info.RDRAM = rdram;
gfx_info.DMEM = DMEM;
gfx_info.IMEM = IMEM;
gfx_info.MI_INTR_REG = &MI_INTR_REG;
gfx_info.DPC_START_REG = &DPC_START_REG;
gfx_info.DPC_END_REG = &DPC_END_REG;
gfx_info.DPC_CURRENT_REG = &DPC_CURRENT_REG;
gfx_info.DPC_STATUS_REG = &DPC_STATUS_REG;
gfx_info.DPC_CLOCK_REG = &DPC_CLOCK_REG;
gfx_info.DPC_BUFBUSY_REG = &DPC_BUFBUSY_REG;
gfx_info.DPC_PIPEBUSY_REG = &DPC_PIPEBUSY_REG;
gfx_info.DPC_TMEM_REG = &DPC_TMEM_REG;
gfx_info.VI_STATUS_REG = &VI_STATUS_REG;
gfx_info.VI_ORIGIN_REG = &VI_ORIGIN_REG;
gfx_info.VI_WIDTH_REG = &VI_WIDTH_REG;
gfx_info.VI_INTR_REG = &VI_INTR_REG;
gfx_info.VI_V_CURRENT_LINE_REG = &VI_V_CURRENT_LINE_REG;
gfx_info.VI_TIMING_REG = &VI_TIMING_REG;
gfx_info.VI_V_SYNC_REG = &VI_V_SYNC_REG;
gfx_info.VI_H_SYNC_REG = &VI_H_SYNC_REG;
gfx_info.VI_LEAP_REG = &VI_LEAP_REG;
gfx_info.VI_H_START_REG = &VI_H_START_REG;
gfx_info.VI_V_START_REG = &VI_V_START_REG;
gfx_info.VI_V_BURST_REG = &VI_V_BURST_REG;
gfx_info.VI_X_SCALE_REG = &VI_X_SCALE_REG;
gfx_info.VI_Y_SCALE_REG = &VI_Y_SCALE_REG;
gfx_info.CheckInterrupts = dummy_check_interrupts;
gfx_info.version = 2;
gfx_info.SP_STATUS_REG = &SP_STATUS_REG;
gfx_info.RDRAM_SIZE = &RDRAM_SIZE;
InitiateGFX(gfx_info);
}
void RT64SendDL(uint8_t* rdram, const OSTask* task) {
OSTask task_copy = *task;
task_copy.t.data_ptr &= 0x3FFFFFF;
task_copy.t.ucode &= 0x3FFFFFF;
task_copy.t.ucode_data &= 0x3FFFFFF;
memcpy(DMEM + 0xFC0, &task_copy, 0x40);
ProcessDList();
}
void RT64UpdateScreen(uint32_t vi_origin) {
VI_ORIGIN_REG = vi_origin;
UpdateScreen();
}
+50
View File
@@ -0,0 +1,50 @@
#include <cstdio>
#include <fstream>
#include "../portultra/multilibultra.hpp"
#include "recomp.h"
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);
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);
}
// For debugging
if (dump_frame) {
char addr_str[32];
constexpr size_t ram_size = 0x800000;
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};
for (size_t i = 0; i < ram_size; i++) {
ram_unswapped[i] = rdram[i ^ 3];
}
dump_file.write(ram_unswapped.get(), ram_size);
dump_frame = false;
}
Multilibultra::submit_rsp_task(rdram, ctx->r4);
}
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) {
// 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) {
assert(false);
}
+38
View File
@@ -0,0 +1,38 @@
#include "../portultra/multilibultra.hpp"
#include "recomp.h"
extern "C" void osViSetYScale_recomp(uint8_t* rdram, recomp_context * ctx) {
;
}
extern "C" void osViSetXScale_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 osViSetSpecialFeatures_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) {
ctx->r2 = (gpr)(int32_t)osViGetNextFramebuffer();
}
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) {
;
}