Implemented audio ucode recomp and audio interface, removed restrict usage due to issues with release builds

This commit is contained in:
Mr-Wiseguy 2023-02-15 17:59:25 -05:00
parent 217a30b032
commit 7babd24bd1
25 changed files with 447 additions and 235 deletions

View file

@ -11,6 +11,7 @@
using InstrId = rabbitizer::InstrId::UniqueId; using InstrId = rabbitizer::InstrId::UniqueId;
using Cop0Reg = rabbitizer::Registers::Rsp::Cop0; using Cop0Reg = rabbitizer::Registers::Rsp::Cop0;
constexpr size_t instr_size = sizeof(uint32_t); constexpr size_t instr_size = sizeof(uint32_t);
constexpr uint32_t rsp_mem_mask = 0x1FFF;
// Can't use rabbitizer's operand types because we need to be able to provide a register reference or a register index // Can't use rabbitizer's operand types because we need to be able to provide a register reference or a register index
enum class RspOperand { enum class RspOperand {
@ -126,6 +127,8 @@ uint32_t expected_c0_reg_value(int cop0_reg) {
return 0; // Pretend DMAs complete instantly return 0; // Pretend DMAs complete instantly
case Cop0Reg::RSP_COP0_SP_SEMAPHORE: case Cop0Reg::RSP_COP0_SP_SEMAPHORE:
return 0; // Always acquire the semaphore return 0; // Always acquire the semaphore
case Cop0Reg::RSP_COP0_DPC_STATUS:
return 0; // Good enough for the microcodes that would be recompiled (i.e. non-graphics ones)
} }
fmt::print(stderr, "Unhandled mfc0: {}\n", cop0_reg); fmt::print(stderr, "Unhandled mfc0: {}\n", cop0_reg);
assert(false); assert(false);
@ -175,7 +178,7 @@ BranchTargets get_branch_targets(const std::vector<rabbitizer::InstructionRsp>&
BranchTargets ret; BranchTargets ret;
for (const auto& instr : instrs) { for (const auto& instr : instrs) {
if (instr.isJumpWithAddress() || instr.isBranch()) { if (instr.isJumpWithAddress() || instr.isBranch()) {
ret.direct_targets.insert(instr.getBranchVramGeneric()); ret.direct_targets.insert(instr.getBranchVramGeneric() & rsp_mem_mask);
} }
if (instr.doesLink()) { if (instr.doesLink()) {
ret.indirect_targets.insert(instr.getVram() + 2 * instr_size); ret.indirect_targets.insert(instr.getVram() + 2 * instr_size);
@ -184,22 +187,27 @@ BranchTargets get_branch_targets(const std::vector<rabbitizer::InstructionRsp>&
return ret; return ret;
} }
bool process_instruction(size_t instr_index, const std::vector<rabbitizer::InstructionRsp>& instructions, std::ofstream& output_file, const BranchTargets& branch_targets, bool indent) { bool process_instruction(size_t instr_index, const std::vector<rabbitizer::InstructionRsp>& instructions, std::ofstream& output_file, const BranchTargets& branch_targets, bool indent, bool in_delay_slot) {
const auto& instr = instructions[instr_index]; const auto& instr = instructions[instr_index];
uint32_t instr_vram = instr.getVram(); uint32_t instr_vram = instr.getVram();
InstrId instr_id = instr.getUniqueId(); InstrId instr_id = instr.getUniqueId();
// Print a label if one exists here // Skip labels if we're duplicating an instruction into a delay slot
if (branch_targets.direct_targets.contains(instr_vram) || branch_targets.indirect_targets.contains(instr_vram)) { if (!in_delay_slot) {
fmt::print(output_file, "L_{:08X}:\n", instr_vram); // Print a label if one exists here
if (branch_targets.direct_targets.contains(instr_vram) || branch_targets.indirect_targets.contains(instr_vram)) {
fmt::print(output_file, "L_{:04X}:\n", instr_vram);
}
} }
uint16_t branch_target = instr.getBranchVramGeneric() & rsp_mem_mask;
// Output a comment with the original instruction // Output a comment with the original instruction
if (instr.isBranch() || instr_id == InstrId::rsp_j) { if (instr.isBranch() || instr_id == InstrId::rsp_j) {
fmt::print(output_file, " // {}\n", instr.disassemble(0, fmt::format("L_{:08X}", (uint32_t)instr.getBranchVramGeneric()))); fmt::print(output_file, " // {}\n", instr.disassemble(0, fmt::format("L_{:04X}", branch_target)));
} else if (instr_id == InstrId::rsp_jal) { } else if (instr_id == InstrId::rsp_jal) {
fmt::print(output_file, " // {}\n", instr.disassemble(0, fmt::format("0x{:08X}", (uint32_t)instr.getBranchVramGeneric()))); fmt::print(output_file, " // {}\n", instr.disassemble(0, fmt::format("0x{:04X}", branch_target)));
} else { } else {
fmt::print(output_file, " // {}\n", instr.disassemble(0)); fmt::print(output_file, " // {}\n", instr.disassemble(0));
} }
@ -222,7 +230,7 @@ bool process_instruction(size_t instr_index, const std::vector<rabbitizer::Instr
auto print_unconditional_branch = [&]<typename... Ts>(fmt::format_string<Ts...> fmt_str, Ts ...args) { auto print_unconditional_branch = [&]<typename... Ts>(fmt::format_string<Ts...> fmt_str, Ts ...args) {
if (instr_index < instructions.size() - 1) { if (instr_index < instructions.size() - 1) {
uint32_t next_vram = instr_vram + 4; uint32_t next_vram = instr_vram + 4;
process_instruction(instr_index + 1, instructions, output_file, branch_targets, false); process_instruction(instr_index + 1, instructions, output_file, branch_targets, false, true);
} }
print_indent(); print_indent();
fmt::print(output_file, fmt_str, args...); fmt::print(output_file, fmt_str, args...);
@ -233,7 +241,7 @@ bool process_instruction(size_t instr_index, const std::vector<rabbitizer::Instr
fmt::print(output_file, "{{\n "); fmt::print(output_file, "{{\n ");
if (instr_index < instructions.size() - 1) { if (instr_index < instructions.size() - 1) {
uint32_t next_vram = instr_vram + 4; uint32_t next_vram = instr_vram + 4;
process_instruction(instr_index + 1, instructions, output_file, branch_targets, true); process_instruction(instr_index + 1, instructions, output_file, branch_targets, true, true);
} }
fmt::print(output_file, " "); fmt::print(output_file, " ");
fmt::print(output_file, fmt_str, args...); fmt::print(output_file, fmt_str, args...);
@ -421,11 +429,11 @@ bool process_instruction(size_t instr_index, const std::vector<rabbitizer::Instr
// Branches // Branches
case InstrId::rsp_j: case InstrId::rsp_j:
case InstrId::rsp_b: case InstrId::rsp_b:
print_unconditional_branch("goto L_{:08X}", instr.getBranchVramGeneric()); print_unconditional_branch("goto L_{:04X}", branch_target);
break; break;
case InstrId::rsp_jal: case InstrId::rsp_jal:
print_line("{}{} = 0x{:08X}", ctx_gpr_prefix(31), 31, instr_vram + 2 * instr_size); print_line("{}{} = 0x{:04X}", ctx_gpr_prefix(31), 31, instr_vram + 2 * instr_size);
print_unconditional_branch("goto L_{:08X}", instr.getBranchVramGeneric()); print_unconditional_branch("goto L_{:04X}", branch_target);
break; break;
case InstrId::rsp_jr: case InstrId::rsp_jr:
print_line("jump_target = {}{}", ctx_gpr_prefix(rs), rs); print_line("jump_target = {}{}", ctx_gpr_prefix(rs), rs);
@ -438,32 +446,32 @@ bool process_instruction(size_t instr_index, const std::vector<rabbitizer::Instr
case InstrId::rsp_bne: case InstrId::rsp_bne:
print_indent(); print_indent();
print_branch_condition("if ({}{} != {}{})", ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt); print_branch_condition("if ({}{} != {}{})", ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
print_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric()); print_branch("goto L_{:04X}", branch_target);
break; break;
case InstrId::rsp_beq: case InstrId::rsp_beq:
print_indent(); print_indent();
print_branch_condition("if ({}{} == {}{})", ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt); print_branch_condition("if ({}{} == {}{})", ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
print_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric()); print_branch("goto L_{:04X}", branch_target);
break; break;
case InstrId::rsp_bgez: case InstrId::rsp_bgez:
print_indent(); print_indent();
print_branch_condition("if (RSP_SIGNED({}{}) >= 0)", ctx_gpr_prefix(rs), rs); print_branch_condition("if (RSP_SIGNED({}{}) >= 0)", ctx_gpr_prefix(rs), rs);
print_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric()); print_branch("goto L_{:04X}", branch_target);
break; break;
case InstrId::rsp_bgtz: case InstrId::rsp_bgtz:
print_indent(); print_indent();
print_branch_condition("if (RSP_SIGNED({}{}) > 0)", ctx_gpr_prefix(rs), rs); print_branch_condition("if (RSP_SIGNED({}{}) > 0)", ctx_gpr_prefix(rs), rs);
print_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric()); print_branch("goto L_{:04X}", branch_target);
break; break;
case InstrId::rsp_blez: case InstrId::rsp_blez:
print_indent(); print_indent();
print_branch_condition("if (RSP_SIGNED({}{}) <= 0)", ctx_gpr_prefix(rs), rs); print_branch_condition("if (RSP_SIGNED({}{}) <= 0)", ctx_gpr_prefix(rs), rs);
print_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric()); print_branch("goto L_{:04X}", branch_target);
break; break;
case InstrId::rsp_bltz: case InstrId::rsp_bltz:
print_indent(); print_indent();
print_branch_condition("if (RSP_SIGNED({}{}) < 0)", ctx_gpr_prefix(rs), rs); print_branch_condition("if (RSP_SIGNED({}{}) < 0)", ctx_gpr_prefix(rs), rs);
print_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric()); print_branch("goto L_{:04X}", branch_target);
break; break;
case InstrId::rsp_break: case InstrId::rsp_break:
print_line("return RspExitReason::Broke", instr_vram); print_line("return RspExitReason::Broke", instr_vram);
@ -492,9 +500,9 @@ bool process_instruction(size_t instr_index, const std::vector<rabbitizer::Instr
void write_indirect_jumps(std::ofstream& output_file, const BranchTargets& branch_targets) { void write_indirect_jumps(std::ofstream& output_file, const BranchTargets& branch_targets) {
fmt::print(output_file, fmt::print(output_file,
"do_indirect_jump:\n" "do_indirect_jump:\n"
" switch (jump_target) {{ \n"); " switch (jump_target & {:#X}) {{ \n", rsp_mem_mask);
for (uint32_t branch_target: branch_targets.indirect_targets) { for (uint32_t branch_target: branch_targets.indirect_targets) {
fmt::print(output_file, " case 0x{0:08X}: goto L_{0:08X};\n", branch_target); fmt::print(output_file, " case 0x{0:04X}: goto L_{0:04X};\n", branch_target);
} }
fmt::print(output_file, fmt::print(output_file,
" }}\n" " }}\n"
@ -502,12 +510,21 @@ void write_indirect_jumps(std::ofstream& output_file, const BranchTargets& branc
} }
// TODO de-hardcode these // TODO de-hardcode these
constexpr size_t rsp_text_offset = 0xB8BAD0; //constexpr size_t rsp_text_offset = 0xB8BAD0;
constexpr size_t rsp_text_size = 0xAF0; //constexpr size_t rsp_text_size = 0xAF0;
constexpr size_t rsp_text_address = 0x04001080; //constexpr size_t rsp_text_address = 0x04001080;
//std::string rom_file_path = "../test/oot_mq_debug.z64";
//std::string output_file_path = "../test/rsp/njpgdspMain.cpp";
//std::string output_function_name = "njpgdspMain";
//const std::vector<uint32_t> extra_indirect_branch_targets{};
constexpr size_t rsp_text_offset = 0xB89260;
constexpr size_t rsp_text_size = 0xFB0;
constexpr size_t rsp_text_address = 0x04001000;
std::string rom_file_path = "../test/oot_mq_debug.z64"; std::string rom_file_path = "../test/oot_mq_debug.z64";
std::string output_file_path = "../test/rsp/njpgdspMain.cpp"; std::string output_file_path = "../test/rsp/aspMain.cpp";
std::string output_function_name = "njpgdspMain"; std::string output_function_name = "aspMain";
const std::vector<uint32_t> extra_indirect_branch_targets{ 0x1F68, 0x1230, 0x114C, 0x1F18, 0x1E2C, 0x14F4, 0x1E9C, 0x1CB0, 0x117C, 0x17CC, 0x11E8, 0x1AA4, 0x1B34, 0x1190, 0x1C5C, 0x1220, 0x1784, 0x1830, 0x1A20, 0x1884, 0x1A84, 0x1A94, 0x1A48, 0x1BA0 };
#ifdef _MSC_VER #ifdef _MSC_VER
inline uint32_t byteswap(uint32_t val) { inline uint32_t byteswap(uint32_t val) {
@ -544,7 +561,7 @@ int main() {
// Decode the instruction words into instructions // Decode the instruction words into instructions
std::vector<rabbitizer::InstructionRsp> instrs{}; std::vector<rabbitizer::InstructionRsp> instrs{};
instrs.reserve(instr_words.size()); instrs.reserve(instr_words.size());
uint32_t vram = rsp_text_address; uint32_t vram = rsp_text_address & rsp_mem_mask;
for (uint32_t instr_word : instr_words) { for (uint32_t instr_word : instr_words) {
const rabbitizer::InstructionRsp& instr = instrs.emplace_back(byteswap(instr_word), vram); const rabbitizer::InstructionRsp& instr = instrs.emplace_back(byteswap(instr_word), vram);
vram += instr_size; vram += instr_size;
@ -553,6 +570,11 @@ int main() {
// Collect indirect jump targets (return addresses for linked jumps) // Collect indirect jump targets (return addresses for linked jumps)
BranchTargets branch_targets = get_branch_targets(instrs); BranchTargets branch_targets = get_branch_targets(instrs);
// Add any additional indirect branch targets that may not be found directly in the code (e.g. from a jump table)
for (uint32_t target : extra_indirect_branch_targets) {
branch_targets.indirect_targets.insert(target);
}
// Open output file and write beginning // Open output file and write beginning
std::ofstream output_file(output_file_path); std::ofstream output_file(output_file_path);
fmt::print(output_file, fmt::print(output_file,
@ -568,7 +590,7 @@ int main() {
" r1 = 0xFC0;\n", output_function_name); " r1 = 0xFC0;\n", output_function_name);
// Write each instruction // Write each instruction
for (size_t instr_index = 0; instr_index < instrs.size(); instr_index++) { for (size_t instr_index = 0; instr_index < instrs.size(); instr_index++) {
process_instruction(instr_index, instrs, output_file, branch_targets, false); process_instruction(instr_index, instrs, output_file, branch_targets, false, false);
} }
// Terminate instruction code with a return to indicate that the microcode has run past its end // Terminate instruction code with a return to indicate that the microcode has run past its end

View file

@ -173,14 +173,13 @@ typedef struct {
} recomp_context; } recomp_context;
#ifdef __cplusplus #ifdef __cplusplus
#define restrict __restrict
extern "C" { extern "C" {
#endif #endif
void switch_error(const char* func, uint32_t vram, uint32_t jtbl); void switch_error(const char* func, uint32_t vram, uint32_t jtbl);
void do_break(uint32_t vram); void do_break(uint32_t vram);
typedef void (recomp_func_t)(uint8_t* restrict rdram, recomp_context* restrict ctx); typedef void (recomp_func_t)(uint8_t* rdram, recomp_context* ctx);
recomp_func_t* get_function(int32_t vram); recomp_func_t* get_function(int32_t vram);

View file

@ -992,7 +992,7 @@ int main(int argc, char** argv) {
if (!func.ignored && func.words.size() != 0) { if (!func.ignored && func.words.size() != 0) {
fmt::print(func_header_file, fmt::print(func_header_file,
"void {}(uint8_t* restrict rdram, recomp_context* restrict ctx);\n", func.name); "void {}(uint8_t* rdram, recomp_context* ctx);\n", func.name);
//fmt::print(lookup_file, //fmt::print(lookup_file,
// " {{ 0x{:08X}u, {} }},\n", func.vram, func.name); // " {{ 0x{:08X}u, {} }},\n", func.vram, func.name);
if (RecompPort::recompile_function(context, func, output_dir + func.name + ".c", static_funcs_by_section) == false) { if (RecompPort::recompile_function(context, func, output_dir + func.name + ".c", static_funcs_by_section) == false) {
@ -1002,7 +1002,7 @@ int main(int argc, char** argv) {
} }
} else if (func.reimplemented) { } else if (func.reimplemented) {
fmt::print(func_header_file, fmt::print(func_header_file,
"void {}(uint8_t* restrict rdram, recomp_context* restrict ctx);\n", func.name); "void {}(uint8_t* rdram, recomp_context* ctx);\n", func.name);
//fmt::print(lookup_file, //fmt::print(lookup_file,
// " {{ 0x{:08X}u, {} }},\n", func.vram, func.name); // " {{ 0x{:08X}u, {} }},\n", func.vram, func.name);
} }
@ -1058,7 +1058,7 @@ int main(int argc, char** argv) {
}; };
fmt::print(func_header_file, fmt::print(func_header_file,
"void {}(uint8_t* restrict rdram, recomp_context* restrict ctx);\n", func.name); "void {}(uint8_t* rdram, recomp_context* ctx);\n", func.name);
//fmt::print(lookup_file, //fmt::print(lookup_file,
// " {{ 0x{:08X}u, {} }},\n", func.vram, func.name); // " {{ 0x{:08X}u, {} }},\n", func.vram, func.name);
if (RecompPort::recompile_function(context, func, output_dir + func.name + ".c", static_funcs_by_section) == false) { if (RecompPort::recompile_function(context, func, output_dir + func.name + ".c", static_funcs_by_section) == false) {

View file

@ -978,7 +978,7 @@ bool RecompPort::recompile_function(const RecompPort::Context& context, const Re
"#include \"recomp.h\"\n" "#include \"recomp.h\"\n"
"#include \"disable_warnings.h\"\n" "#include \"disable_warnings.h\"\n"
"\n" "\n"
"void {}(uint8_t* restrict rdram, recomp_context* restrict ctx) {{\n" "void {}(uint8_t* rdram, recomp_context* ctx) {{\n"
// these variables shouldn't need to be preserved across function boundaries, so make them local for more efficient output // these variables shouldn't need to be preserved across function boundaries, so make them local for more efficient output
" uint64_t hi = 0, lo = 0, result = 0;\n" " uint64_t hi = 0, lo = 0, result = 0;\n"
" int c1cs = 0; \n", // cop1 conditional signal " int c1cs = 0; \n", // cop1 conditional signal

View file

@ -93,6 +93,10 @@
</PrecompiledHeaderFile> </PrecompiledHeaderFile>
<AdditionalIncludeDirectories>$(SolutionDir)..</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(SolutionDir)..</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation> <MultiProcessorCompilation>true</MultiProcessorCompilation>
<Optimization>Disabled</Optimization>
<AdditionalOptions>
</AdditionalOptions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem> <SubSystem>
@ -134,6 +138,8 @@
<AdditionalIncludeDirectories>$(SolutionDir)..</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(SolutionDir)..</AdditionalIncludeDirectories>
<PrecompiledHeaderFile /> <PrecompiledHeaderFile />
<MultiProcessorCompilation>true</MultiProcessorCompilation> <MultiProcessorCompilation>true</MultiProcessorCompilation>
<Optimization>Disabled</Optimization>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem> <SubSystem>
@ -155,6 +161,7 @@
<AdditionalIncludeDirectories>$(SolutionDir)..</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(SolutionDir)..</AdditionalIncludeDirectories>
<PrecompiledHeaderFile /> <PrecompiledHeaderFile />
<MultiProcessorCompilation>true</MultiProcessorCompilation> <MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>false</WholeProgramOptimization>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem> <SubSystem>

View file

@ -153,6 +153,11 @@ XCOPY "$(ProjectDir)Lib\SDL2-2.24.0\lib\$(Platform)\SDL2.dll" "$(TargetDir)" /S
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="funcs\lookup.cpp" /> <ClCompile Include="funcs\lookup.cpp" />
<ClCompile Include="portultra\audio.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
</ClCompile>
<ClCompile Include="portultra\events.cpp" /> <ClCompile Include="portultra\events.cpp" />
<ClCompile Include="portultra\timer.cpp" /> <ClCompile Include="portultra\timer.cpp" />
<ClCompile Include="portultra\ultrainit.cpp" /> <ClCompile Include="portultra\ultrainit.cpp" />
@ -162,7 +167,22 @@ XCOPY "$(ProjectDir)Lib\SDL2-2.24.0\lib\$(Platform)\SDL2.dll" "$(TargetDir)" /S
<ClCompile Include="portultra\task_pthreads.cpp" /> <ClCompile Include="portultra\task_pthreads.cpp" />
<ClCompile Include="portultra\task_win32.cpp" /> <ClCompile Include="portultra\task_win32.cpp" />
<ClCompile Include="portultra\threads.cpp" /> <ClCompile Include="portultra\threads.cpp" />
<ClCompile Include="rsp\njpgdspMain.cpp" /> <ClCompile Include="rsp\aspMain.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
<SupportJustMyCode Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</SupportJustMyCode>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AnySuitable</InlineFunctionExpansion>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AnySuitable</InlineFunctionExpansion>
</ClCompile>
<ClCompile Include="rsp\njpgdspMain.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
<SupportJustMyCode Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</SupportJustMyCode>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AnySuitable</InlineFunctionExpansion>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AnySuitable</InlineFunctionExpansion>
</ClCompile>
<ClCompile Include="RT64\rt64_layer.cpp" /> <ClCompile Include="RT64\rt64_layer.cpp" />
<ClCompile Include="src\ai.cpp" /> <ClCompile Include="src\ai.cpp" />
<ClCompile Include="src\cont.cpp" /> <ClCompile Include="src\cont.cpp" />

View file

@ -30237,6 +30237,12 @@
<ClCompile Include="rsp\njpgdspMain.cpp"> <ClCompile Include="rsp\njpgdspMain.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="rsp\aspMain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="portultra\audio.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="portultra\platform_specific.h"> <ClInclude Include="portultra\platform_specific.h">

142
test/portultra/audio.cpp Normal file
View file

@ -0,0 +1,142 @@
#include "ultra64.h"
#include "multilibultra.hpp"
#include "SDL.h"
#include "SDL_audio.h"
#include <cassert>
static SDL_AudioDeviceID audio_device = 0;
void Multilibultra::init_audio() {
// Initialize SDL audio.
SDL_InitSubSystem(SDL_INIT_AUDIO);
// Pick an initial dummy sample rate; this will be set by the game later to the true sample rate.
set_audio_frequency(48000);
}
void SDLCALL feed_audio(void* userdata, Uint8* stream, int len);
void Multilibultra::set_audio_frequency(uint32_t freq) {
if (audio_device != 0) {
SDL_CloseAudioDevice(audio_device);
}
SDL_AudioSpec spec_desired{
.freq = (int)freq,
.format = AUDIO_S16,
.channels = 2,
.silence = 0, // calculated
.samples = 0x100, // Fairly small sample count to reduce the latency of internal buffering
.padding = 0, // unused
.size = 0, // calculated
.callback = feed_audio, // Use a callback as QueueAudio causes popping
.userdata = nullptr
};
audio_device = SDL_OpenAudioDevice(nullptr, false, &spec_desired, nullptr, 0);
if (audio_device == 0) {
printf("SDL Error: %s\n", SDL_GetError());
fflush(stdout);
assert(false);
}
SDL_PauseAudioDevice(audio_device, 0);
}
// Struct representing a queued audio buffer.
struct AudioBuffer {
// All samples in the buffer, including those that have already been sent.
std::vector<int16_t> samples;
// The count of samples that have already been sent to the audio device.
size_t used_samples = 0;
// Helper methods.
size_t remaining_samples() const { return samples.size() - used_samples; };
size_t remaining_bytes() const { return remaining_samples() * sizeof(samples[0]); };
int16_t* first_unused_sample() { return &samples[used_samples]; }
bool empty() { return used_samples == samples.size(); }
};
// Mutex for locking the queued audio buffer list.
std::mutex audio_buffers_mutex;
// The queued audio buffer list, holds a list of buffers that have been queued by the game.
std::vector<AudioBuffer> audio_buffers;
void SDLCALL feed_audio(void* userdata, Uint8* stream, int byte_count) {
// Ensure that the byte count is an integer multiple of samples.
assert((byte_count & 1) == 0);
// Calculate the sample count from the byte count.
size_t remaining_samples = byte_count / sizeof(int16_t);
// Lock the queued audio buffer list.
std::lock_guard lock{ audio_buffers_mutex };
// Empty the audio buffers until we've sent all the required samples
// or until there are no samples left in the audio buffers.
while (!audio_buffers.empty() && remaining_samples > 0) {
auto& cur_buffer = audio_buffers.front();
// Prevent overrunning either the input or output buffer.
size_t to_copy = std::min(remaining_samples, cur_buffer.remaining_samples());
// Copy samples from the input buffer to the output one.
memcpy(stream, cur_buffer.first_unused_sample(), to_copy * sizeof(int16_t));
// Advance the output buffer by the copied byte count.
stream += to_copy * sizeof(int16_t);
// Advance the input buffer by the copied sample count.
cur_buffer.used_samples += to_copy;
// Updated the remaining sample count.
remaining_samples -= to_copy;
// If the input buffer was emptied, remove it from the list of queued buffers.
if (cur_buffer.empty()) {
audio_buffers.erase(audio_buffers.begin());
}
}
// Zero out any remaining audio data to lessen audio issues during lag
memset(stream, 0, remaining_samples * sizeof(int16_t));
}
void Multilibultra::queue_audio_buffer(RDRAM_ARG PTR(s16) audio_data_, uint32_t byte_count) {
// Ensure that the byte count is an integer multiple of samples.
assert((byte_count & 1) == 0);
s16* audio_data = TO_PTR(s16, audio_data_);
// Calculate the number of samples from the number of bytes.
uint32_t sample_count = byte_count / sizeof(s16);
// Lock the queued audio buffer list.
std::lock_guard lock{ audio_buffers_mutex };
// Set up a new queued audio buffer.
AudioBuffer& new_buf = audio_buffers.emplace_back();
new_buf.samples.resize(sample_count);
new_buf.used_samples = 0;
// Copy the data into the new buffer.
// Swap the audio channels to correct for the address xor caused by endianness handling.
for (size_t i = 0; i < sample_count; i += 2) {
new_buf.samples[i + 0] = audio_data[i + 1];
new_buf.samples[i + 1] = audio_data[i + 0];
}
}
// If there's ever any audio popping, check here first. Some games are very sensitive to
// the remaining sample count and reporting a number that's too high here can lead to issues.
// Reporting a number that's too low can lead to audio lag in some games.
uint32_t Multilibultra::get_remaining_audio_bytes() {
// Calculate the number of samples still in the queued audio buffers
size_t buffered_byte_count = 0;
{
// Lock the queued audio buffer list.
std::lock_guard lock{ audio_buffers_mutex };
// Gather the remaining byte count of the next buffer, if any exists.
if (!audio_buffers.empty()) {
buffered_byte_count = audio_buffers.front().remaining_bytes();
}
}
// Add the number of remaining bytes in the audio data that's been sent to the device.
buffered_byte_count += SDL_GetQueuedAudioSize(audio_device);
// Add a slight positive scaling bias, which helps audio respond quicker. Remove the bias
// if games have popping issues.
return buffered_byte_count + (buffered_byte_count / 10);
}

View file

@ -210,6 +210,7 @@ uint16_t rspInverseSquareRoots[512];
using RspUcodeFunc = RspExitReason(uint8_t* rdram); using RspUcodeFunc = RspExitReason(uint8_t* rdram);
extern RspUcodeFunc njpgdspMain; extern RspUcodeFunc njpgdspMain;
extern RspUcodeFunc aspMain;
// From Ares emulator. For license details, see rsp_vu.h // From Ares emulator. For license details, see rsp_vu.h
void rsp_constants_init() { void rsp_constants_init() {
@ -269,7 +270,7 @@ void event_thread_func(uint8_t* rdram, uint8_t* rom) {
sp_complete(); sp_complete();
dp_complete(); dp_complete();
} else if (task_action->task.t.type == M_AUDTASK) { } else if (task_action->task.t.type == M_AUDTASK) {
sp_complete(); run_rsp_microcode(rdram, &task_action->task, aspMain);
} else if (task_action->task.t.type == M_NJPEGTASK) { } else if (task_action->task.t.type == M_NJPEGTASK) {
run_rsp_microcode(rdram, &task_action->task, njpgdspMain); run_rsp_microcode(rdram, &task_action->task, njpgdspMain);
} else { } else {

View file

@ -47,6 +47,10 @@ void send_si_message();
uint32_t get_speed_multiplier(); uint32_t get_speed_multiplier();
std::chrono::system_clock::time_point get_start(); std::chrono::system_clock::time_point get_start();
std::chrono::system_clock::duration time_since_start(); std::chrono::system_clock::duration time_since_start();
void init_audio();
void set_audio_frequency(uint32_t freq);
void queue_audio_buffer(RDRAM_ARG PTR(s16) audio_data, uint32_t byte_count);
uint32_t get_remaining_audio_bytes();
class preemption_guard { class preemption_guard {
public: public:

View file

@ -5,6 +5,7 @@ void Multilibultra::preinit(uint8_t* rdram, uint8_t* rom) {
Multilibultra::set_main_thread(); Multilibultra::set_main_thread();
Multilibultra::init_events(rdram, rom); Multilibultra::init_events(rdram, rom);
Multilibultra::init_timers(rdram); Multilibultra::init_timers(rdram);
Multilibultra::init_audio();
Multilibultra::save_init(); Multilibultra::save_init();
} }

1
test/rsp/.gitignore vendored
View file

@ -1 +1,2 @@
njpgdspMain.cpp njpgdspMain.cpp
aspMain.cpp

View file

@ -1,20 +1,29 @@
#include "recomp.h" #include "recomp.h"
#include <cstdio>
#include <string>
#include "../portultra/ultra64.h"
#include "../portultra/multilibultra.hpp"
extern "C" void osAiSetFrequency_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { #define VI_NTSC_CLOCK 48681812
ctx->r2 = ctx->r4;
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);
} }
static uint32_t ai_length = 0; extern "C" void osAiSetNextBuffer_recomp(uint8_t* rdram, recomp_context* ctx) {
Multilibultra::queue_audio_buffer(rdram, ctx->r4, ctx->r5);
extern "C" void osAiSetNextBuffer_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {
ai_length = (uint32_t)ctx->r5;
ctx->r2 = 0; ctx->r2 = 0;
} }
extern "C" void osAiGetLength_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osAiGetLength_recomp(uint8_t* rdram, recomp_context* ctx) {
ctx->r2 = ai_length; ctx->r2 = Multilibultra::get_remaining_audio_bytes();
} }
extern "C" void osAiGetStatus_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osAiGetStatus_recomp(uint8_t* rdram, recomp_context* ctx) {
ctx->r2 = 0x80000000; ctx->r2 = 0x00000000; // Pretend the audio DMAs finish instantly
} }

View file

@ -3,7 +3,7 @@
static int max_controllers = 0; static int max_controllers = 0;
extern "C" void osContInit_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osContInit_recomp(uint8_t* rdram, recomp_context* ctx) {
gpr bitpattern = ctx->r5; gpr bitpattern = ctx->r5;
gpr status = ctx->r6; gpr status = ctx->r6;
@ -26,7 +26,7 @@ extern "C" void osContInit_recomp(uint8_t* restrict rdram, recomp_context* restr
ctx->r2 = 0; ctx->r2 = 0;
} }
extern "C" void osContStartReadData_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osContStartReadData_recomp(uint8_t* rdram, recomp_context* ctx) {
Multilibultra::send_si_message(); Multilibultra::send_si_message();
} }
@ -49,7 +49,7 @@ void release_button(int button) {
} }
extern "C" void osContGetReadData_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osContGetReadData_recomp(uint8_t* rdram, recomp_context* ctx) {
int32_t pad = (int32_t)ctx->r4; int32_t pad = (int32_t)ctx->r4;
if (max_controllers > 0) { if (max_controllers > 0) {
@ -67,11 +67,11 @@ extern "C" void osContGetReadData_recomp(uint8_t* restrict rdram, recomp_context
} }
} }
extern "C" void osContStartQuery_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { extern "C" void osContStartQuery_recomp(uint8_t * rdram, recomp_context * ctx) {
Multilibultra::send_si_message(); Multilibultra::send_si_message();
} }
extern "C" void osContGetQuery_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { extern "C" void osContGetQuery_recomp(uint8_t * rdram, recomp_context * ctx) {
gpr status = ctx->r4; gpr status = ctx->r4;
// Mark controller 0 as present // Mark controller 0 as present
@ -86,23 +86,23 @@ extern "C" void osContGetQuery_recomp(uint8_t * restrict rdram, recomp_context *
} }
} }
extern "C" void osContSetCh_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osContSetCh_recomp(uint8_t* rdram, recomp_context* ctx) {
max_controllers = std::min((unsigned int)ctx->r4, 4u); max_controllers = std::min((unsigned int)ctx->r4, 4u);
ctx->r2 = 0; ctx->r2 = 0;
} }
extern "C" void __osMotorAccess_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void __osMotorAccess_recomp(uint8_t* rdram, recomp_context* ctx) {
} }
extern "C" void osMotorInit_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osMotorInit_recomp(uint8_t* rdram, recomp_context* ctx) {
; ;
} }
extern "C" void osMotorStart_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osMotorStart_recomp(uint8_t* rdram, recomp_context* ctx) {
; ;
} }
extern "C" void osMotorStop_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osMotorStop_recomp(uint8_t* rdram, recomp_context* ctx) {
; ;
} }

View file

@ -1,5 +1,5 @@
#include "recomp.h" #include "recomp.h"
extern "C" void osDpSetNextBuffer_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osDpSetNextBuffer_recomp(uint8_t* rdram, recomp_context* ctx) {
; ;
} }

View file

@ -1,21 +1,21 @@
#include "recomp.h" #include "recomp.h"
extern "C" void osEepromProbe_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osEepromProbe_recomp(uint8_t* rdram, recomp_context* ctx) {
; ;
} }
extern "C" void osEepromWrite_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osEepromWrite_recomp(uint8_t* rdram, recomp_context* ctx) {
; ;
} }
extern "C" void osEepromLongWrite_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osEepromLongWrite_recomp(uint8_t* rdram, recomp_context* ctx) {
; ;
} }
extern "C" void osEepromRead_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osEepromRead_recomp(uint8_t* rdram, recomp_context* ctx) {
; ;
} }
extern "C" void osEepromLongRead_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osEepromLongRead_recomp(uint8_t* rdram, recomp_context* ctx) {
; ;
} }

View file

@ -2,7 +2,7 @@
#include "recomp.h" #include "recomp.h"
extern "C" void __udivdi3_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { extern "C" void __udivdi3_recomp(uint8_t * rdram, recomp_context * ctx) {
uint64_t a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu); uint64_t a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu);
uint64_t b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu); uint64_t b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu);
uint64_t ret = a / b; uint64_t ret = a / b;
@ -11,7 +11,7 @@ extern "C" void __udivdi3_recomp(uint8_t * restrict rdram, recomp_context * rest
ctx->r3 = (int32_t)(ret >> 0); ctx->r3 = (int32_t)(ret >> 0);
} }
extern "C" void __divdi3_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { extern "C" void __divdi3_recomp(uint8_t * rdram, recomp_context * ctx) {
int64_t a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu); int64_t a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu);
int64_t b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu); int64_t b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu);
int64_t ret = a / b; int64_t ret = a / b;
@ -20,7 +20,7 @@ extern "C" void __divdi3_recomp(uint8_t * restrict rdram, recomp_context * restr
ctx->r3 = (int32_t)(ret >> 0); ctx->r3 = (int32_t)(ret >> 0);
} }
extern "C" void __umoddi3_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { extern "C" void __umoddi3_recomp(uint8_t * rdram, recomp_context * ctx) {
uint64_t a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu); uint64_t a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu);
uint64_t b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu); uint64_t b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu);
uint64_t ret = a % b; uint64_t ret = a % b;
@ -29,7 +29,7 @@ extern "C" void __umoddi3_recomp(uint8_t * restrict rdram, recomp_context * rest
ctx->r3 = (int32_t)(ret >> 0); ctx->r3 = (int32_t)(ret >> 0);
} }
extern "C" void __ull_div_recomp(uint8_t * restrict rdram, recomp_context * restrict 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 a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu);
uint64_t b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu); uint64_t b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu);
uint64_t ret = a / b; uint64_t ret = a / b;
@ -38,7 +38,7 @@ extern "C" void __ull_div_recomp(uint8_t * restrict rdram, recomp_context * rest
ctx->r3 = (int32_t)(ret >> 0); ctx->r3 = (int32_t)(ret >> 0);
} }
extern "C" void __ll_div_recomp(uint8_t * restrict rdram, recomp_context * restrict 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 a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu);
int64_t b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu); int64_t b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu);
int64_t ret = a / b; int64_t ret = a / b;
@ -47,7 +47,7 @@ extern "C" void __ll_div_recomp(uint8_t * restrict rdram, recomp_context * restr
ctx->r3 = (int32_t)(ret >> 0); ctx->r3 = (int32_t)(ret >> 0);
} }
extern "C" void __ll_mul_recomp(uint8_t * restrict rdram, recomp_context * restrict 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 a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu);
uint64_t b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu); uint64_t b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu);
uint64_t ret = a * b; uint64_t ret = a * b;
@ -56,7 +56,7 @@ extern "C" void __ll_mul_recomp(uint8_t * restrict rdram, recomp_context * restr
ctx->r3 = (int32_t)(ret >> 0); ctx->r3 = (int32_t)(ret >> 0);
} }
extern "C" void __ull_rem_recomp(uint8_t * restrict rdram, recomp_context * restrict 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 a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu);
uint64_t b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu); uint64_t b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu);
uint64_t ret = a % b; uint64_t ret = a % b;
@ -65,14 +65,14 @@ extern "C" void __ull_rem_recomp(uint8_t * restrict rdram, recomp_context * rest
ctx->r3 = (int32_t)(ret >> 0); ctx->r3 = (int32_t)(ret >> 0);
} }
extern "C" void __ull_to_d_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { extern "C" void __ull_to_d_recomp(uint8_t * rdram, recomp_context * ctx) {
uint64_t a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu); uint64_t a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu);
double ret = (double)a; double ret = (double)a;
ctx->f0.d = ret; ctx->f0.d = ret;
} }
extern "C" void __ull_to_f_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { extern "C" void __ull_to_f_recomp(uint8_t * rdram, recomp_context * ctx) {
uint64_t a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu); uint64_t a = (ctx->r4 << 32) | ((ctx->r5 << 0) & 0xFFFFFFFFu);
float ret = (float)a; float ret = (float)a;

View file

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

View file

@ -58,7 +58,7 @@ constexpr int32_t cart_handle = 0x80800000;
extern std::unique_ptr<uint8_t[]> rom; extern std::unique_ptr<uint8_t[]> rom;
extern size_t rom_size; extern size_t rom_size;
extern "C" void osCartRomInit_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osCartRomInit_recomp(uint8_t* rdram, recomp_context* ctx) {
OSPiHandle* handle = TO_PTR(OSPiHandle, cart_handle); OSPiHandle* handle = TO_PTR(OSPiHandle, cart_handle);
handle->type = 0; // cart handle->type = 0; // cart
handle->baseAddress = phys_to_k1(rom_base); handle->baseAddress = phys_to_k1(rom_base);
@ -67,7 +67,7 @@ extern "C" void osCartRomInit_recomp(uint8_t* restrict rdram, recomp_context* re
ctx->r2 = (gpr)cart_handle; ctx->r2 = (gpr)cart_handle;
} }
extern "C" void osCreatePiManager_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osCreatePiManager_recomp(uint8_t* rdram, recomp_context* ctx) {
; ;
} }
@ -83,7 +83,7 @@ void do_rom_read(uint8_t* rdram, gpr ram_address, uint32_t physical_addr, size_t
std::array<char, 0x20000> save_buffer; std::array<char, 0x20000> save_buffer;
const char save_filename[] = "save.bin"; const char save_filename[] = "save.bin";
void save_write(uint8_t* restrict rdram, gpr rdram_address, uint32_t offset, uint32_t count) { void save_write(uint8_t* rdram, gpr rdram_address, uint32_t offset, uint32_t count) {
for (uint32_t i = 0; i < count; i++) { for (uint32_t i = 0; i < count; i++) {
save_buffer[offset + i] = MEM_B(i, rdram_address); save_buffer[offset + i] = MEM_B(i, rdram_address);
} }
@ -97,7 +97,7 @@ void save_write(uint8_t* restrict rdram, gpr rdram_address, uint32_t offset, uin
} }
} }
void save_read(uint8_t* restrict 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) {
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
MEM_B(i, rdram_address) = save_buffer[offset + i]; MEM_B(i, rdram_address) = save_buffer[offset + i];
} }
@ -113,7 +113,7 @@ void Multilibultra::save_init() {
} }
} }
void do_dma(uint8_t* restrict rdram, PTR(OSMesgQueue) mq, gpr rdram_address, uint32_t physical_addr, uint32_t size, uint32_t direction) { 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 asynchronous transfer
// TODO implement unaligned DMA correctly // TODO implement unaligned DMA correctly
if (direction == 0) { if (direction == 0) {
@ -148,7 +148,7 @@ void do_dma(uint8_t* restrict rdram, PTR(OSMesgQueue) mq, gpr rdram_address, uin
} }
} }
extern "C" void osPiStartDma_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osPiStartDma_recomp(uint8_t* rdram, recomp_context* ctx) {
uint32_t mb = ctx->r4; uint32_t mb = ctx->r4;
uint32_t pri = ctx->r5; uint32_t pri = ctx->r5;
uint32_t direction = ctx->r6; uint32_t direction = ctx->r6;
@ -165,7 +165,7 @@ extern "C" void osPiStartDma_recomp(uint8_t* restrict rdram, recomp_context* res
ctx->r2 = 0; ctx->r2 = 0;
} }
extern "C" void osEPiStartDma_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osEPiStartDma_recomp(uint8_t* rdram, recomp_context* ctx) {
OSPiHandle* handle = TO_PTR(OSPiHandle, ctx->r4); OSPiHandle* handle = TO_PTR(OSPiHandle, ctx->r4);
OSIoMesg* mb = TO_PTR(OSIoMesg, ctx->r5); OSIoMesg* mb = TO_PTR(OSIoMesg, ctx->r5);
uint32_t direction = ctx->r6; uint32_t direction = ctx->r6;
@ -182,7 +182,7 @@ extern "C" void osEPiStartDma_recomp(uint8_t* restrict rdram, recomp_context* re
ctx->r2 = 0; ctx->r2 = 0;
} }
extern "C" void osEPiReadIo_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { extern "C" void osEPiReadIo_recomp(uint8_t * rdram, recomp_context * ctx) {
OSPiHandle* handle = TO_PTR(OSPiHandle, ctx->r4); OSPiHandle* handle = TO_PTR(OSPiHandle, ctx->r4);
uint32_t devAddr = handle->baseAddress | ctx->r5; uint32_t devAddr = handle->baseAddress | ctx->r5;
gpr dramAddr = ctx->r6; gpr dramAddr = ctx->r6;
@ -199,10 +199,10 @@ extern "C" void osEPiReadIo_recomp(uint8_t * restrict rdram, recomp_context * re
ctx->r2 = 0; ctx->r2 = 0;
} }
extern "C" void osPiGetStatus_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { extern "C" void osPiGetStatus_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = 0; ctx->r2 = 0;
} }
extern "C" void osPiRawStartDma_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { extern "C" void osPiRawStartDma_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = 0; ctx->r2 = 0;
} }

View file

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

View file

@ -3,31 +3,31 @@
#include "recomp.h" #include "recomp.h"
#include "euc-jp.h" #include "euc-jp.h"
extern "C" void __checkHardware_msp_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { extern "C" void __checkHardware_msp_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = 0; ctx->r2 = 0;
} }
extern "C" void __checkHardware_kmc_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { extern "C" void __checkHardware_kmc_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = 0; ctx->r2 = 0;
} }
extern "C" void __checkHardware_isv_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { extern "C" void __checkHardware_isv_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = 0; ctx->r2 = 0;
} }
extern "C" void __osInitialize_msp_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { extern "C" void __osInitialize_msp_recomp(uint8_t * rdram, recomp_context * ctx) {
} }
extern "C" void __osInitialize_kmc_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { extern "C" void __osInitialize_kmc_recomp(uint8_t * rdram, recomp_context * ctx) {
} }
extern "C" void __osInitialize_isv_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { extern "C" void __osInitialize_isv_recomp(uint8_t * rdram, recomp_context * ctx) {
} }
extern "C" void isPrintfInit_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { extern "C" void isPrintfInit_recomp(uint8_t * rdram, recomp_context * ctx) {
} }
extern "C" void __osRdbSend_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { extern "C" void __osRdbSend_recomp(uint8_t * rdram, recomp_context * ctx) {
gpr buf = ctx->r4; gpr buf = ctx->r4;
size_t size = ctx->r5; size_t size = ctx->r5;
u32 type = (u32)ctx->r6; u32 type = (u32)ctx->r6;
@ -43,7 +43,7 @@ extern "C" void __osRdbSend_recomp(uint8_t * restrict rdram, recomp_context * re
ctx->r2 = size; ctx->r2 = size;
} }
extern "C" void is_proutSyncPrintf_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { extern "C" void is_proutSyncPrintf_recomp(uint8_t * rdram, recomp_context * ctx) {
// Buffering to speed up print performance // Buffering to speed up print performance
static std::vector<char> print_buffer; static std::vector<char> print_buffer;
@ -51,17 +51,17 @@ extern "C" void is_proutSyncPrintf_recomp(uint8_t * restrict rdram, recomp_conte
size_t size = ctx->r6; size_t size = ctx->r6;
for (size_t i = 0; i < size; i++) { for (size_t i = 0; i < size; i++) {
// Add the new character to the buffer // Add the new character to the buffer
char cur_char = MEM_B(i, buf); char cur_char = MEM_B(i, buf);
// If the new character is a newline, flush the buffer // If the new character is a newline, flush the buffer
if (cur_char == '\n') { if (cur_char == '\n') {
std::string utf8_str = Encoding::decode_eucjp(std::string_view{ print_buffer.data(), print_buffer.size() }); std::string utf8_str = Encoding::decode_eucjp(std::string_view{ print_buffer.data(), print_buffer.size() });
puts(utf8_str.c_str()); puts(utf8_str.c_str());
print_buffer.clear(); print_buffer.clear();
} else { } else {
print_buffer.push_back(cur_char); print_buffer.push_back(cur_char);
} }
} }
//fwrite(to_print.get(), size, 1, stdout); //fwrite(to_print.get(), size, 1, stdout);

View file

@ -21,7 +21,7 @@ constexpr uint32_t byteswap(uint32_t val) {
} }
#endif #endif
extern "C" void _bzero(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void _bzero(uint8_t* rdram, recomp_context* ctx) {
gpr start_addr = ctx->r4; gpr start_addr = ctx->r4;
gpr size = ctx->r5; gpr size = ctx->r5;
@ -30,7 +30,7 @@ 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) { extern "C" void osGetMemSize_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = 8 * 1024 * 1024; ctx->r2 = 8 * 1024 * 1024;
} }
@ -58,7 +58,7 @@ std::unique_ptr<uint8_t[]> rom;
size_t rom_size; size_t rom_size;
// Recomp generation functions // Recomp generation functions
extern "C" void recomp_entrypoint(uint8_t * restrict rdram, recomp_context * restrict ctx); extern "C" void recomp_entrypoint(uint8_t * rdram, recomp_context * ctx);
gpr get_entrypoint_address(); gpr get_entrypoint_address();
const char* get_rom_name(); const char* get_rom_name();
void init_overlays(); void init_overlays();

View file

@ -91,7 +91,7 @@ struct RSP {
auto set(u32 index, bool value) -> bool { return u16(index) = 0 - value, value; } auto set(u32 index, bool value) -> bool { return u16(index) = 0 - value, value; }
//vu-registers.cpp //vu-registers.cpp
auto operator()(u32 index) const -> r128; inline auto operator()(u32 index) const -> r128;
}; };
using cr128 = const r128; using cr128 = const r128;
@ -109,91 +109,91 @@ struct RSP {
static constexpr r128 zero{0}; static constexpr r128 zero{0};
static constexpr r128 invert{(uint64_t)-1, (uint64_t)-1}; static constexpr r128 invert{(uint64_t)-1, (uint64_t)-1};
auto accumulatorGet(u32 index) const -> u64; inline auto accumulatorGet(u32 index) const -> u64;
auto accumulatorSet(u32 index, u64 value) -> void; inline auto accumulatorSet(u32 index, u64 value) -> void;
auto accumulatorSaturate(u32 index, bool slice, u16 negative, u16 positive) const -> u16; inline auto accumulatorSaturate(u32 index, bool slice, u16 negative, u16 positive) const -> u16;
auto CFC2(r32& rt, u8 rd) -> void; inline auto CFC2(r32& rt, u8 rd) -> void;
auto CTC2(cr32& rt, u8 rd) -> void; inline auto CTC2(cr32& rt, u8 rd) -> void;
template<u8 e> auto LBV(r128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto LBV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto LDV(r128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto LDV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto LFV(r128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto LFV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto LHV(r128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto LHV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto LLV(r128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto LLV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto LPV(r128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto LPV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto LQV(r128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto LQV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto LRV(r128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto LRV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto LSV(r128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto LSV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto LTV(u8 vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto LTV(u8 vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto LUV(r128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto LUV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto LWV(r128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto LWV(r128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto MFC2(r32& rt, cr128& vs) -> void; template<u8 e> inline auto MFC2(r32& rt, cr128& vs) -> void;
template<u8 e> auto MTC2(cr32& rt, r128& vs) -> void; template<u8 e> inline auto MTC2(cr32& rt, r128& vs) -> void;
template<u8 e> auto SBV(cr128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto SBV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto SDV(cr128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto SDV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto SFV(cr128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto SFV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto SHV(cr128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto SHV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto SLV(cr128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto SLV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto SPV(cr128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto SPV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto SQV(cr128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto SQV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto SRV(cr128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto SRV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto SSV(cr128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto SSV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto STV(u8 vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto STV(u8 vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto SUV(cr128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto SUV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto SWV(cr128& vt, cr32& rs, s8 imm) -> void; template<u8 e> inline auto SWV(cr128& vt, cr32& rs, s8 imm) -> void;
template<u8 e> auto VABS(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VABS(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VADD(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VADD(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VADDC(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VADDC(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VAND(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VAND(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VCH(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VCH(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VCL(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VCL(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VCR(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VCR(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VEQ(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VEQ(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VGE(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VGE(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VLT(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VLT(r128& vd, cr128& vs, cr128& vt) -> void;
template<bool U, u8 e> template<bool U, u8 e>
auto VMACF(r128& vd, cr128& vs, cr128& vt) -> void; inline auto VMACF(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VMACF(r128& vd, cr128& vs, cr128& vt) -> void { VMACF<0, e>(vd, vs, vt); } template<u8 e> inline auto VMACF(r128& vd, cr128& vs, cr128& vt) -> void { VMACF<0, e>(vd, vs, vt); }
template<u8 e> auto VMACU(r128& vd, cr128& vs, cr128& vt) -> void { VMACF<1, e>(vd, vs, vt); } template<u8 e> inline auto VMACU(r128& vd, cr128& vs, cr128& vt) -> void { VMACF<1, e>(vd, vs, vt); }
auto VMACQ(r128& vd) -> void; inline auto VMACQ(r128& vd) -> void;
template<u8 e> auto VMADH(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VMADH(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VMADL(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VMADL(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VMADM(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VMADM(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VMADN(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VMADN(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VMOV(r128& vd, u8 de, cr128& vt) -> void; template<u8 e> inline auto VMOV(r128& vd, u8 de, cr128& vt) -> void;
template<u8 e> auto VMRG(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VMRG(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VMUDH(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VMUDH(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VMUDL(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VMUDL(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VMUDM(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VMUDM(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VMUDN(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VMUDN(r128& vd, cr128& vs, cr128& vt) -> void;
template<bool U, u8 e> template<bool U, u8 e>
auto VMULF(r128& rd, cr128& vs, cr128& vt) -> void; inline auto VMULF(r128& rd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VMULF(r128& rd, cr128& vs, cr128& vt) -> void { VMULF<0, e>(rd, vs, vt); } template<u8 e> inline auto VMULF(r128& rd, cr128& vs, cr128& vt) -> void { VMULF<0, e>(rd, vs, vt); }
template<u8 e> auto VMULU(r128& rd, cr128& vs, cr128& vt) -> void { VMULF<1, e>(rd, vs, vt); } template<u8 e> inline auto VMULU(r128& rd, cr128& vs, cr128& vt) -> void { VMULF<1, e>(rd, vs, vt); }
template<u8 e> auto VMULQ(r128& rd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VMULQ(r128& rd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VNAND(r128& rd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VNAND(r128& rd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VNE(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VNE(r128& vd, cr128& vs, cr128& vt) -> void;
auto VNOP() -> void; inline auto VNOP() -> void;
template<u8 e> auto VNOR(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VNOR(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VNXOR(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VNXOR(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VOR(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VOR(r128& vd, cr128& vs, cr128& vt) -> void;
template<bool L, u8 e> template<bool L, u8 e>
auto VRCP(r128& vd, u8 de, cr128& vt) -> void; inline auto VRCP(r128& vd, u8 de, cr128& vt) -> void;
template<u8 e> auto VRCP(r128& vd, u8 de, cr128& vt) -> void { VRCP<0, e>(vd, de, vt); } template<u8 e> inline auto VRCP(r128& vd, u8 de, cr128& vt) -> void { VRCP<0, e>(vd, de, vt); }
template<u8 e> auto VRCPL(r128& vd, u8 de, cr128& vt) -> void { VRCP<1, e>(vd, de, vt); } template<u8 e> inline auto VRCPL(r128& vd, u8 de, cr128& vt) -> void { VRCP<1, e>(vd, de, vt); }
template<u8 e> auto VRCPH(r128& vd, u8 de, cr128& vt) -> void; template<u8 e> inline auto VRCPH(r128& vd, u8 de, cr128& vt) -> void;
template<bool D, u8 e> template<bool D, u8 e>
auto VRND(r128& vd, u8 vs, cr128& vt) -> void; inline auto VRND(r128& vd, u8 vs, cr128& vt) -> void;
template<u8 e> auto VRNDN(r128& vd, u8 vs, cr128& vt) -> void { VRND<0, e>(vd, vs, vt); } template<u8 e> inline auto VRNDN(r128& vd, u8 vs, cr128& vt) -> void { VRND<0, e>(vd, vs, vt); }
template<u8 e> auto VRNDP(r128& vd, u8 vs, cr128& vt) -> void { VRND<1, e>(vd, vs, vt); } template<u8 e> inline auto VRNDP(r128& vd, u8 vs, cr128& vt) -> void { VRND<1, e>(vd, vs, vt); }
template<bool L, u8 e> template<bool L, u8 e>
auto VRSQ(r128& vd, u8 de, cr128& vt) -> void; inline auto VRSQ(r128& vd, u8 de, cr128& vt) -> void;
template<u8 e> auto VRSQ(r128& vd, u8 de, cr128& vt) -> void { VRSQ<0, e>(vd, de, vt); } template<u8 e> inline auto VRSQ(r128& vd, u8 de, cr128& vt) -> void { VRSQ<0, e>(vd, de, vt); }
template<u8 e> auto VRSQL(r128& vd, u8 de, cr128& vt) -> void { VRSQ<1, e>(vd, de, vt); } template<u8 e> inline auto VRSQL(r128& vd, u8 de, cr128& vt) -> void { VRSQ<1, e>(vd, de, vt); }
template<u8 e> auto VRSQH(r128& vd, u8 de, cr128& vt) -> void; template<u8 e> inline auto VRSQH(r128& vd, u8 de, cr128& vt) -> void;
template<u8 e> auto VSAR(r128& vd, cr128& vs) -> void; template<u8 e> inline auto VSAR(r128& vd, cr128& vs) -> void;
template<u8 e> auto VSUB(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VSUB(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VSUBC(r128& vd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VSUBC(r128& vd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VXOR(r128& rd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VXOR(r128& rd, cr128& vs, cr128& vt) -> void;
template<u8 e> auto VZERO(r128& rd, cr128& vs, cr128& vt) -> void; template<u8 e> inline auto VZERO(r128& rd, cr128& vs, cr128& vt) -> void;
}; };

View file

@ -3,13 +3,13 @@
#include "../portultra/multilibultra.hpp" #include "../portultra/multilibultra.hpp"
#include "recomp.h" #include "recomp.h"
extern "C" void osSpTaskLoad_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osSpTaskLoad_recomp(uint8_t* rdram, recomp_context* ctx) {
// Nothing to do here // Nothing to do here
} }
bool dump_frame = false; bool dump_frame = false;
extern "C" void osSpTaskStartGo_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osSpTaskStartGo_recomp(uint8_t* rdram, recomp_context* ctx) {
//printf("[sp] osSpTaskStartGo(0x%08X)\n", (uint32_t)ctx->r4); //printf("[sp] osSpTaskStartGo(0x%08X)\n", (uint32_t)ctx->r4);
OSTask* task = TO_PTR(OSTask, ctx->r4); OSTask* task = TO_PTR(OSTask, ctx->r4);
if (task->t.type == M_GFXTASK) { if (task->t.type == M_GFXTASK) {
@ -35,15 +35,15 @@ extern "C" void osSpTaskStartGo_recomp(uint8_t* restrict rdram, recomp_context*
Multilibultra::submit_rsp_task(rdram, ctx->r4); Multilibultra::submit_rsp_task(rdram, ctx->r4);
} }
extern "C" void osSpTaskYield_recomp(uint8_t* restrict rdram, recomp_context* restrict 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) // Ignore yield requests (acts as if the task completed before it received the yield request)
} }
extern "C" void osSpTaskYielded_recomp(uint8_t* restrict rdram, recomp_context* restrict 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 // Task yield requests are ignored, so always return 0 as tasks will never be yielded
ctx->r2 = 0; ctx->r2 = 0;
} }
extern "C" void __osSpSetPc_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void __osSpSetPc_recomp(uint8_t* rdram, recomp_context* ctx) {
assert(false); assert(false);
} }

View file

@ -1,38 +1,38 @@
#include "../portultra/multilibultra.hpp" #include "../portultra/multilibultra.hpp"
#include "recomp.h" #include "recomp.h"
extern "C" void osViSetYScale_recomp(uint8_t* restrict rdram, recomp_context * restrict ctx) { extern "C" void osViSetYScale_recomp(uint8_t* rdram, recomp_context * ctx) {
; ;
} }
extern "C" void osViSetXScale_recomp(uint8_t* restrict rdram, recomp_context * restrict ctx) { extern "C" void osViSetXScale_recomp(uint8_t* rdram, recomp_context * ctx) {
; ;
} }
extern "C" void osCreateViManager_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osCreateViManager_recomp(uint8_t* rdram, recomp_context* ctx) {
; ;
} }
extern "C" void osViBlack_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osViBlack_recomp(uint8_t* rdram, recomp_context* ctx) {
; ;
} }
extern "C" void osViSetSpecialFeatures_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osViSetSpecialFeatures_recomp(uint8_t* rdram, recomp_context* ctx) {
; ;
} }
extern "C" void osViGetCurrentFramebuffer_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osViGetCurrentFramebuffer_recomp(uint8_t* rdram, recomp_context* ctx) {
ctx->r2 = (gpr)(int32_t)osViGetCurrentFramebuffer(); ctx->r2 = (gpr)(int32_t)osViGetCurrentFramebuffer();
} }
extern "C" void osViGetNextFramebuffer_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osViGetNextFramebuffer_recomp(uint8_t* rdram, recomp_context* ctx) {
ctx->r2 = (gpr)(int32_t)osViGetNextFramebuffer(); ctx->r2 = (gpr)(int32_t)osViGetNextFramebuffer();
} }
extern "C" void osViSwapBuffer_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osViSwapBuffer_recomp(uint8_t* rdram, recomp_context* ctx) {
osViSwapBuffer(rdram, (int32_t)ctx->r4); osViSwapBuffer(rdram, (int32_t)ctx->r4);
} }
extern "C" void osViSetMode_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osViSetMode_recomp(uint8_t* rdram, recomp_context* ctx) {
; ;
} }