More libultra function implementations, euc-jp decoding for print output, improved build times for output project

This commit is contained in:
Mr-Wiseguy 2023-01-16 23:01:21 -05:00
parent c6de2b6189
commit d2603ce07c
26 changed files with 30090 additions and 238 deletions

View file

@ -1,18 +1,26 @@
#include "../portultra/multilibultra.hpp"
#include "recomp.h"
static int max_controllers = 0;
extern "C" void osContInit_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {
gpr bitpattern = ctx->r5;
gpr status = ctx->r6;
// Set bit 0 to indicate that controller 0 is present
MEM_B(0, bitpattern) = 0x01;
MEM_H(0, status) = 0x0005; // CONT_TYPE_NORMAL
MEM_B(2, status) = 0; // controller status
MEM_B(3, status) = 0; // controller errno
// 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)
// Write CHNL_ERR_NORESP for the other controllers
for (size_t controller = 1; controller < 4; controller++) {
MEM_B(4 * controller + 3, status) = 0x80;
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;
@ -42,19 +50,44 @@ void release_button(int button) {
}
extern "C" void osContGetReadData_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {
int32_t pad = (uint32_t)ctx->r4;
int32_t pad = (int32_t)ctx->r4;
// 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;
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 * restrict rdram, recomp_context * restrict ctx) {
Multilibultra::send_si_message();
}
extern "C" void osContGetQuery_recomp(uint8_t * restrict rdram, recomp_context * restrict 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* restrict rdram, recomp_context* restrict ctx) {
max_controllers = std::min((unsigned int)ctx->r4, 4u);
ctx->r2 = 0;
}

2587
test/src/euc-jp.cpp Normal file

File diff suppressed because it is too large Load diff

11
test/src/euc-jp.h Normal file
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

View file

@ -3,8 +3,8 @@
extern "C" void __udivdi3_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
uint64_t a = (ctx->r4 << 32) | (ctx->r5 << 0);
uint64_t b = (ctx->r6 << 32) | (ctx->r7 << 0);
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);
@ -12,8 +12,8 @@ extern "C" void __udivdi3_recomp(uint8_t * restrict rdram, recomp_context * rest
}
extern "C" void __divdi3_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
int64_t a = (ctx->r4 << 32) | (ctx->r5 << 0);
int64_t b = (ctx->r6 << 32) | (ctx->r7 << 0);
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);
@ -21,8 +21,8 @@ extern "C" void __divdi3_recomp(uint8_t * restrict rdram, recomp_context * restr
}
extern "C" void __umoddi3_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
uint64_t a = (ctx->r4 << 32) | (ctx->r5 << 0);
uint64_t b = (ctx->r6 << 32) | (ctx->r7 << 0);
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);
@ -30,8 +30,8 @@ extern "C" void __umoddi3_recomp(uint8_t * restrict rdram, recomp_context * rest
}
extern "C" void __ull_div_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
uint64_t a = (ctx->r4 << 32) | (ctx->r5 << 0);
uint64_t b = (ctx->r6 << 32) | (ctx->r7 << 0);
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);
@ -39,8 +39,8 @@ extern "C" void __ull_div_recomp(uint8_t * restrict rdram, recomp_context * rest
}
extern "C" void __ll_div_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
int64_t a = (ctx->r4 << 32) | (ctx->r5 << 0);
int64_t b = (ctx->r6 << 32) | (ctx->r7 << 0);
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);
@ -48,8 +48,8 @@ extern "C" void __ll_div_recomp(uint8_t * restrict rdram, recomp_context * restr
}
extern "C" void __ll_mul_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
uint64_t a = (ctx->r4 << 32) | (ctx->r5 << 0);
uint64_t b = (ctx->r6 << 32) | (ctx->r7 << 0);
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);
@ -57,8 +57,8 @@ extern "C" void __ll_mul_recomp(uint8_t * restrict rdram, recomp_context * restr
}
extern "C" void __ull_rem_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
uint64_t a = (ctx->r4 << 32) | (ctx->r5 << 0);
uint64_t b = (ctx->r6 << 32) | (ctx->r7 << 0);
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);
@ -66,14 +66,14 @@ extern "C" void __ull_rem_recomp(uint8_t * restrict rdram, recomp_context * rest
}
extern "C" void __ull_to_d_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
uint64_t a = (ctx->r4 << 32) | (ctx->r5 << 0);
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 * restrict rdram, recomp_context * restrict ctx) {
uint64_t a = (ctx->r4 << 32) | (ctx->r5 << 0);
uint64_t a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu);
float ret = (float)a;
ctx->f0.fl = ret;

98
test/src/overlays.cpp Normal file
View file

@ -0,0 +1,98 @@
#include <unordered_map>
#include <algorithm>
#include <vector>
#include "recomp.h"
#include "../funcs/recomp_overlays.inl"
constexpr size_t num_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);
}
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_sections], rom,
[](const SectionTableEntry& entry, uint32_t addr) {
return entry.rom_addr < addr;
}
);
auto upper = std::upper_bound(&section_table[0], &section_table[num_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);
}
// Remove the section from the loaded section map
it = loaded_sections.erase(it);
// Skip incrementing the iterator
continue;
}
++it;
}
}
void init_overlays() {
// Sort the executable sections by rom address
std::sort(&section_table[0], &section_table[num_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
test/src/pak.cpp Normal file
View file

@ -0,0 +1,31 @@
#include "recomp.h"
#include "../portultra/ultra64.h"
#include "../portultra/multilibultra.hpp"
extern "C" void osPfsInitPak_recomp(uint8_t * restrict rdram, recomp_context* restrict ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK
}
extern "C" void osPfsFreeBlocks_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK
}
extern "C" void osPfsAllocateFile_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK
}
extern "C" void osPfsDeleteFile_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK
}
extern "C" void osPfsFileState_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK
}
extern "C" void osPfsFindFile_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK
}
extern "C" void osPfsReadWriteFile_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK
}

View file

@ -3,49 +3,6 @@
#include "../portultra/ultra64.h"
#include "../portultra/multilibultra.hpp"
extern std::unique_ptr<uint8_t[]> rom;
extern size_t rom_size;
extern "C" void osCartRomInit_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {
;
}
extern "C" void osCreatePiManager_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {
;
}
constexpr uint32_t rom_base = 0xB0000000;
void do_rom_read(uint8_t* rdram, gpr ram_address, uint32_t dev_address, size_t num_bytes) {
// TODO use word copies when possible
uint8_t* rom_addr = rom.get() + (dev_address | rom_base) - rom_base;
for (size_t i = 0; i < num_bytes; i++) {
MEM_B(i, ram_address) = *rom_addr;
rom_addr++;
}
}
extern "C" void osPiStartDma_recomp(uint8_t* restrict rdram, recomp_context* restrict 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);
debug_printf("[pi] DMA from 0x%08X into 0x%08X of size 0x%08X\n", devAddr, dramAddr, size);
// TODO asynchronous transfer (will require preemption in the scheduler)
// TODO this won't handle unaligned DMA
do_rom_read(rdram, dramAddr, devAddr, size);
//memcpy(rdram + (dramAddr & 0x3FFFFFF), rom.get() + (devAddr | rom_base) - rom_base, num_bytes);
// Send a message to the mq to indicate that the transfer completed
osSendMesg(rdram, mq, 0, OS_MESG_NOBLOCK);
}
struct OSIoMesgHdr {
// These 3 reversed due to endianness
u8 status; /* Return status */
@ -62,24 +19,148 @@ struct OSIoMesg {
u32 piHandle; /* PI device handle */
};
extern "C" void osEPiStartDma_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {
OSIoMesg* mb = TO_PTR(OSIoMesg, ctx->r5);
struct OSPiHandle {
PTR(OSPiHandle_s) unused; /* point to next handle on the table */
// These four members reversed due to endianness
u8 relDuration; /* domain release duration */
u8 pageSize; /* domain page size */
u8 latency; /* domain latency */
u8 type; /* DEVICE_TYPE_BULK for disk */
// These three members reversed due to endianness
u16 padding; /* struct alignment padding */
u8 domain; /* which domain */
u8 pulse; /* domain pulse width */
u32 baseAddress; /* Domain address */
u32 speed; /* for roms only */
/* The following are "private" elements" */
u32 transferInfo[18]; /* for disk only */
};
// 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;
}
// We need a place in rdram to hold the cart handle, so pick an address in extended rdram
constexpr int32_t cart_handle = 0x80800000;
extern std::unique_ptr<uint8_t[]> rom;
extern size_t rom_size;
extern "C" void osCartRomInit_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {
OSPiHandle* handle = TO_PTR(OSPiHandle, cart_handle);
handle->type = 0; // cart
handle->baseAddress = phys_to_k1(rom_base);
handle->domain = 0;
ctx->r2 = (gpr)cart_handle;
}
extern "C" void osCreatePiManager_recomp(uint8_t* restrict rdram, recomp_context* restrict 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++;
}
}
void do_dma(uint8_t* restrict 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 {
// read sram
printf("[WARN] SRAM read unimplemented, returning zeroes\n");
for (uint32_t i = 0; i < size; i++) {
MEM_B(i, rdram_address) = 0;
}
// Send a message to the mq to indicate that the transfer completed
osSendMesg(rdram, mq, 0, OS_MESG_NOBLOCK);
}
} else {
if (physical_addr > rom_base) {
// write cart rom
throw std::runtime_error("ROM DMA write unimplemented");
} else {
// write sram
printf("[WARN] SRAM write unimplemented, ignoring data\n");
// Send a message to the mq to indicate that the transfer completed
osSendMesg(rdram, mq, 0, OS_MESG_NOBLOCK);
}
}
}
extern "C" void osPiStartDma_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {
uint32_t mb = ctx->r4;
uint32_t pri = ctx->r5;
uint32_t direction = ctx->r6;
uint32_t devAddr = mb->devAddr;
gpr dramAddr = mb->dramAddr;
uint32_t size = mb->size;
PTR(OSMesgQueue) mq = mb->hdr.retQueue;
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);
// TODO asynchronous transfer (will require preemption in the scheduler)
// TODO this won't handle unaligned DMA
do_rom_read(rdram, dramAddr, devAddr, size);
do_dma(rdram, mq, dramAddr, physical_addr, size, direction);
//memcpy(rdram + (dramAddr & 0x3FFFFFF), rom.get() + (devAddr | rom_base) - rom_base, num_bytes);
ctx->r2 = 0;
}
// Send a message to the mq to indicate that the transfer completed
osSendMesg(rdram, mq, 0, OS_MESG_NOBLOCK);
extern "C" void osEPiStartDma_recomp(uint8_t* restrict rdram, recomp_context* restrict 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 * restrict rdram, recomp_context * restrict 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 * restrict rdram, recomp_context * restrict ctx) {
@ -87,5 +168,5 @@ extern "C" void osPiGetStatus_recomp(uint8_t * restrict rdram, recomp_context *
}
extern "C" void osPiRawStartDma_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
;
}
ctx->r2 = 0;
}

View file

@ -70,8 +70,18 @@ extern "C" void osGetCount_recomp(uint8_t * restrict rdram, recomp_context * res
extern "C" void osGetTime_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
uint64_t total_count = osGetTime();
ctx->r2 = (uint32_t)(total_count >> 32);
ctx->r3 = (int32_t)(total_count >> 0);
ctx->r2 = (int32_t)(total_count >> 32);
ctx->r3 = (int32_t)(total_count >> 0);
}
extern "C" void osSetTimer_recomp(uint8_t * restrict rdram, recomp_context * restrict 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 * restrict rdram, recomp_context * restrict ctx) {
ctx->r2 = osStopTimer(rdram, (int32_t)ctx->r4);
}
extern "C" void osVirtualToPhysical_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
@ -110,43 +120,6 @@ extern "C" void __osSetFpcCsr_recomp(uint8_t * restrict rdram, recomp_context *
ctx->r2 = 0;
}
extern "C" void __checkHardware_msp_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
ctx->r2 = 0;
}
extern "C" void __checkHardware_kmc_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
ctx->r2 = 0;
}
extern "C" void __checkHardware_isv_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
ctx->r2 = 0;
}
extern "C" void __osInitialize_msp_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
}
extern "C" void __osInitialize_kmc_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
}
extern "C" void __osInitialize_isv_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
}
extern "C" void __osRdbSend_recomp(uint8_t * restrict rdram, recomp_context * restrict 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);
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;
}
// For the Mario Party games (not working)
//extern "C" void longjmp_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
// RecompJmpBuf* buf = TO_PTR(RecompJmpBuf, ctx->r4);

70
test/src/print.cpp Normal file
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 * restrict rdram, recomp_context * restrict ctx) {
ctx->r2 = 0;
}
extern "C" void __checkHardware_kmc_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
ctx->r2 = 0;
}
extern "C" void __checkHardware_isv_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
ctx->r2 = 0;
}
extern "C" void __osInitialize_msp_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
}
extern "C" void __osInitialize_kmc_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
}
extern "C" void __osInitialize_isv_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
}
extern "C" void isPrintfInit_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
}
extern "C" void __osRdbSend_recomp(uint8_t * restrict rdram, recomp_context * restrict 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 * restrict rdram, recomp_context * restrict 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;
}

View file

@ -1,4 +1,4 @@
#ifdef _WIN32
#ifdef _WIN32
#include <Windows.h>
#endif
#include <cstdio>
@ -7,6 +7,7 @@
#include <cmath>
#include <unordered_map>
#include <fstream>
#include <iostream>
#include "recomp.h"
#include "../portultra/multilibultra.hpp"
@ -20,20 +21,6 @@ constexpr uint32_t byteswap(uint32_t val) {
}
#endif
extern std::pair<uint32_t, recomp_func_t*> funcs[];
extern const size_t num_funcs;
std::unordered_map<uint32_t, recomp_func_t*> func_map{};
extern "C" recomp_func_t* get_function(uint32_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;
}
extern "C" void _bzero(uint8_t* restrict rdram, recomp_context* restrict ctx) {
gpr start_addr = ctx->r4;
gpr size = ctx->r5;
@ -43,6 +30,10 @@ extern "C" void _bzero(uint8_t* restrict rdram, recomp_context* restrict ctx) {
}
}
extern "C" void osGetMemSize_recomp(uint8_t * restrict rdram, recomp_context * restrict 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);
@ -70,6 +61,13 @@ size_t rom_size;
extern "C" void recomp_entrypoint(uint8_t * restrict rdram, recomp_context * restrict 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) {
@ -77,6 +75,24 @@ int main(int argc, char **argv) {
// 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 };
@ -96,24 +112,28 @@ int main(int argc, char **argv) {
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();
// Allocate rdram_buffer
std::unique_ptr<uint8_t[]> rdram_buffer = std::make_unique<uint8_t[]>(8 * 1024 * 1024);
// 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
do_rom_read(rdram_buffer.get(), entrypoint, 0x1000, 0x100000);
//std::copy_n(rom.get() + 0x1000, 0x100000, rdram_buffer.get() + entrypoint - 0x80000000);
// Initialize function address map
for (size_t i = 0; i < num_funcs; i++) {
func_map[funcs[i].first] = funcs[i].second;
}
// 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;

View file

@ -15,7 +15,7 @@ extern "C" void osSpTaskStartGo_recomp(uint8_t* restrict rdram, recomp_context*
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] Audio task: %08X\n", (uint32_t)ctx->r4);
}
// For debugging
if (dump_frame) {

View file

@ -1,7 +1,11 @@
#include "../portultra/multilibultra.hpp"
#include "recomp.h"
extern "C" void osViSetYScale_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) {
extern "C" void osViSetYScale_recomp(uint8_t* restrict rdram, recomp_context * restrict ctx) {
;
}
extern "C" void osViSetXScale_recomp(uint8_t* restrict rdram, recomp_context * restrict ctx) {
;
}
@ -18,11 +22,11 @@ extern "C" void osViSetSpecialFeatures_recomp(uint8_t* restrict rdram, recomp_co
}
extern "C" void osViGetCurrentFramebuffer_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {
;
ctx->r2 = (gpr)(int32_t)osViGetCurrentFramebuffer();
}
extern "C" void osViGetNextFramebuffer_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {
;
ctx->r2 = (gpr)(int32_t)osViGetNextFramebuffer();
}
extern "C" void osViSwapBuffer_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {