Implemented audio ucode recomp and audio interface, removed restrict usage due to issues with release builds
This commit is contained in:
parent
217a30b032
commit
7babd24bd1
|
@ -11,6 +11,7 @@
|
|||
using InstrId = rabbitizer::InstrId::UniqueId;
|
||||
using Cop0Reg = rabbitizer::Registers::Rsp::Cop0;
|
||||
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
|
||||
enum class RspOperand {
|
||||
|
@ -126,6 +127,8 @@ uint32_t expected_c0_reg_value(int cop0_reg) {
|
|||
return 0; // Pretend DMAs complete instantly
|
||||
case Cop0Reg::RSP_COP0_SP_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);
|
||||
assert(false);
|
||||
|
@ -175,7 +178,7 @@ BranchTargets get_branch_targets(const std::vector<rabbitizer::InstructionRsp>&
|
|||
BranchTargets ret;
|
||||
for (const auto& instr : instrs) {
|
||||
if (instr.isJumpWithAddress() || instr.isBranch()) {
|
||||
ret.direct_targets.insert(instr.getBranchVramGeneric());
|
||||
ret.direct_targets.insert(instr.getBranchVramGeneric() & rsp_mem_mask);
|
||||
}
|
||||
if (instr.doesLink()) {
|
||||
ret.indirect_targets.insert(instr.getVram() + 2 * instr_size);
|
||||
|
@ -184,22 +187,27 @@ BranchTargets get_branch_targets(const std::vector<rabbitizer::InstructionRsp>&
|
|||
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];
|
||||
|
||||
uint32_t instr_vram = instr.getVram();
|
||||
InstrId instr_id = instr.getUniqueId();
|
||||
|
||||
// Skip labels if we're duplicating an instruction into a delay slot
|
||||
if (!in_delay_slot) {
|
||||
// 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_{:08X}:\n", 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
|
||||
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) {
|
||||
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 {
|
||||
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) {
|
||||
if (instr_index < instructions.size() - 1) {
|
||||
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();
|
||||
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 ");
|
||||
if (instr_index < instructions.size() - 1) {
|
||||
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_str, args...);
|
||||
|
@ -421,11 +429,11 @@ bool process_instruction(size_t instr_index, const std::vector<rabbitizer::Instr
|
|||
// Branches
|
||||
case InstrId::rsp_j:
|
||||
case InstrId::rsp_b:
|
||||
print_unconditional_branch("goto L_{:08X}", instr.getBranchVramGeneric());
|
||||
print_unconditional_branch("goto L_{:04X}", branch_target);
|
||||
break;
|
||||
case InstrId::rsp_jal:
|
||||
print_line("{}{} = 0x{:08X}", ctx_gpr_prefix(31), 31, instr_vram + 2 * instr_size);
|
||||
print_unconditional_branch("goto L_{:08X}", instr.getBranchVramGeneric());
|
||||
print_line("{}{} = 0x{:04X}", ctx_gpr_prefix(31), 31, instr_vram + 2 * instr_size);
|
||||
print_unconditional_branch("goto L_{:04X}", branch_target);
|
||||
break;
|
||||
case InstrId::rsp_jr:
|
||||
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:
|
||||
print_indent();
|
||||
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;
|
||||
case InstrId::rsp_beq:
|
||||
print_indent();
|
||||
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;
|
||||
case InstrId::rsp_bgez:
|
||||
print_indent();
|
||||
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;
|
||||
case InstrId::rsp_bgtz:
|
||||
print_indent();
|
||||
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;
|
||||
case InstrId::rsp_blez:
|
||||
print_indent();
|
||||
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;
|
||||
case InstrId::rsp_bltz:
|
||||
print_indent();
|
||||
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;
|
||||
case InstrId::rsp_break:
|
||||
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) {
|
||||
fmt::print(output_file,
|
||||
"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) {
|
||||
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,
|
||||
" }}\n"
|
||||
|
@ -502,12 +510,21 @@ void write_indirect_jumps(std::ofstream& output_file, const BranchTargets& branc
|
|||
}
|
||||
|
||||
// TODO de-hardcode these
|
||||
constexpr size_t rsp_text_offset = 0xB8BAD0;
|
||||
constexpr size_t rsp_text_size = 0xAF0;
|
||||
constexpr size_t rsp_text_address = 0x04001080;
|
||||
//constexpr size_t rsp_text_offset = 0xB8BAD0;
|
||||
//constexpr size_t rsp_text_size = 0xAF0;
|
||||
//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 output_file_path = "../test/rsp/njpgdspMain.cpp";
|
||||
std::string output_function_name = "njpgdspMain";
|
||||
std::string output_file_path = "../test/rsp/aspMain.cpp";
|
||||
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
|
||||
inline uint32_t byteswap(uint32_t val) {
|
||||
|
@ -544,7 +561,7 @@ int main() {
|
|||
// Decode the instruction words into instructions
|
||||
std::vector<rabbitizer::InstructionRsp> instrs{};
|
||||
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) {
|
||||
const rabbitizer::InstructionRsp& instr = instrs.emplace_back(byteswap(instr_word), vram);
|
||||
vram += instr_size;
|
||||
|
@ -553,6 +570,11 @@ int main() {
|
|||
// Collect indirect jump targets (return addresses for linked jumps)
|
||||
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
|
||||
std::ofstream output_file(output_file_path);
|
||||
fmt::print(output_file,
|
||||
|
@ -568,7 +590,7 @@ int main() {
|
|||
" r1 = 0xFC0;\n", output_function_name);
|
||||
// Write each instruction
|
||||
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
|
||||
|
|
3
recomp.h
3
recomp.h
|
@ -173,14 +173,13 @@ typedef struct {
|
|||
} recomp_context;
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define restrict __restrict
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void switch_error(const char* func, uint32_t vram, uint32_t jtbl);
|
||||
void do_break(uint32_t vram);
|
||||
|
||||
typedef void (recomp_func_t)(uint8_t* 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);
|
||||
|
||||
|
|
|
@ -992,7 +992,7 @@ int main(int argc, char** argv) {
|
|||
|
||||
if (!func.ignored && func.words.size() != 0) {
|
||||
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,
|
||||
// " {{ 0x{:08X}u, {} }},\n", func.vram, func.name);
|
||||
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) {
|
||||
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,
|
||||
// " {{ 0x{:08X}u, {} }},\n", func.vram, func.name);
|
||||
}
|
||||
|
@ -1058,7 +1058,7 @@ int main(int argc, char** argv) {
|
|||
};
|
||||
|
||||
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,
|
||||
// " {{ 0x{:08X}u, {} }},\n", func.vram, func.name);
|
||||
if (RecompPort::recompile_function(context, func, output_dir + func.name + ".c", static_funcs_by_section) == false) {
|
||||
|
|
|
@ -978,7 +978,7 @@ bool RecompPort::recompile_function(const RecompPort::Context& context, const Re
|
|||
"#include \"recomp.h\"\n"
|
||||
"#include \"disable_warnings.h\"\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
|
||||
" uint64_t hi = 0, lo = 0, result = 0;\n"
|
||||
" int c1cs = 0; \n", // cop1 conditional signal
|
||||
|
|
|
@ -93,6 +93,10 @@
|
|||
</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)..</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>
|
||||
|
@ -134,6 +138,8 @@
|
|||
<AdditionalIncludeDirectories>$(SolutionDir)..</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeaderFile />
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>
|
||||
|
@ -155,6 +161,7 @@
|
|||
<AdditionalIncludeDirectories>$(SolutionDir)..</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeaderFile />
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>
|
||||
|
|
|
@ -153,6 +153,11 @@ XCOPY "$(ProjectDir)Lib\SDL2-2.24.0\lib\$(Platform)\SDL2.dll" "$(TargetDir)" /S
|
|||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<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\timer.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_win32.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="src\ai.cpp" />
|
||||
<ClCompile Include="src\cont.cpp" />
|
||||
|
|
|
@ -30237,6 +30237,12 @@
|
|||
<ClCompile Include="rsp\njpgdspMain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="rsp\aspMain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="portultra\audio.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="portultra\platform_specific.h">
|
||||
|
|
142
test/portultra/audio.cpp
Normal file
142
test/portultra/audio.cpp
Normal 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);
|
||||
}
|
|
@ -210,6 +210,7 @@ uint16_t rspInverseSquareRoots[512];
|
|||
|
||||
using RspUcodeFunc = RspExitReason(uint8_t* rdram);
|
||||
extern RspUcodeFunc njpgdspMain;
|
||||
extern RspUcodeFunc aspMain;
|
||||
|
||||
// From Ares emulator. For license details, see rsp_vu.h
|
||||
void rsp_constants_init() {
|
||||
|
@ -269,7 +270,7 @@ void event_thread_func(uint8_t* rdram, uint8_t* rom) {
|
|||
sp_complete();
|
||||
dp_complete();
|
||||
} 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) {
|
||||
run_rsp_microcode(rdram, &task_action->task, njpgdspMain);
|
||||
} else {
|
||||
|
|
|
@ -47,6 +47,10 @@ void send_si_message();
|
|||
uint32_t get_speed_multiplier();
|
||||
std::chrono::system_clock::time_point get_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 {
|
||||
public:
|
||||
|
|
|
@ -5,6 +5,7 @@ void Multilibultra::preinit(uint8_t* rdram, uint8_t* rom) {
|
|||
Multilibultra::set_main_thread();
|
||||
Multilibultra::init_events(rdram, rom);
|
||||
Multilibultra::init_timers(rdram);
|
||||
Multilibultra::init_audio();
|
||||
Multilibultra::save_init();
|
||||
}
|
||||
|
||||
|
|
1
test/rsp/.gitignore
vendored
1
test/rsp/.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
njpgdspMain.cpp
|
||||
aspMain.cpp
|
||||
|
|
|
@ -1,20 +1,29 @@
|
|||
#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) {
|
||||
ctx->r2 = ctx->r4;
|
||||
#define VI_NTSC_CLOCK 48681812
|
||||
|
||||
extern "C" void osAiSetFrequency_recomp(uint8_t* rdram, recomp_context* ctx) {
|
||||
uint32_t freq = ctx->r4;
|
||||
// This makes actual audio frequency more accurate to console, but may not be desirable
|
||||
//uint32_t dacRate = (uint32_t)(((float)VI_NTSC_CLOCK / freq) + 0.5f);
|
||||
//freq = VI_NTSC_CLOCK / dacRate;
|
||||
ctx->r2 = freq;
|
||||
Multilibultra::set_audio_frequency(freq);
|
||||
}
|
||||
|
||||
static uint32_t ai_length = 0;
|
||||
|
||||
extern "C" void osAiSetNextBuffer_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {
|
||||
ai_length = (uint32_t)ctx->r5;
|
||||
extern "C" void osAiSetNextBuffer_recomp(uint8_t* rdram, recomp_context* ctx) {
|
||||
Multilibultra::queue_audio_buffer(rdram, ctx->r4, ctx->r5);
|
||||
ctx->r2 = 0;
|
||||
}
|
||||
|
||||
extern "C" void osAiGetLength_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {
|
||||
ctx->r2 = ai_length;
|
||||
extern "C" void osAiGetLength_recomp(uint8_t* rdram, recomp_context* ctx) {
|
||||
ctx->r2 = Multilibultra::get_remaining_audio_bytes();
|
||||
}
|
||||
|
||||
extern "C" void osAiGetStatus_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {
|
||||
ctx->r2 = 0x80000000;
|
||||
extern "C" void osAiGetStatus_recomp(uint8_t* rdram, recomp_context* ctx) {
|
||||
ctx->r2 = 0x00000000; // Pretend the audio DMAs finish instantly
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
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 status = ctx->r6;
|
||||
|
||||
|
@ -26,7 +26,7 @@ extern "C" void osContInit_recomp(uint8_t* restrict rdram, recomp_context* restr
|
|||
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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// 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);
|
||||
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) {
|
||||
;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#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) {
|
||||
;
|
||||
}
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
#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) {
|
||||
;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#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 b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu);
|
||||
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);
|
||||
}
|
||||
|
||||
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 b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu);
|
||||
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);
|
||||
}
|
||||
|
||||
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 b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu);
|
||||
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);
|
||||
}
|
||||
|
||||
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 b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu);
|
||||
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);
|
||||
}
|
||||
|
||||
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 b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu);
|
||||
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);
|
||||
}
|
||||
|
||||
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 b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu);
|
||||
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);
|
||||
}
|
||||
|
||||
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 b = (ctx->r6 << 32) | ((ctx->r7 << 0) & 0xFFFFFFFFu);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
double ret = (double)a;
|
||||
|
||||
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);
|
||||
float ret = (float)a;
|
||||
|
||||
|
|
|
@ -2,30 +2,30 @@
|
|||
#include "../portultra/ultra64.h"
|
||||
#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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ 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) {
|
||||
extern "C" void osCartRomInit_recomp(uint8_t* rdram, recomp_context* ctx) {
|
||||
OSPiHandle* handle = TO_PTR(OSPiHandle, cart_handle);
|
||||
handle->type = 0; // cart
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
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++) {
|
||||
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++) {
|
||||
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 implement unaligned DMA correctly
|
||||
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 pri = ctx->r5;
|
||||
uint32_t direction = ctx->r6;
|
||||
|
@ -165,7 +165,7 @@ extern "C" void osPiStartDma_recomp(uint8_t* restrict rdram, recomp_context* res
|
|||
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);
|
||||
OSIoMesg* mb = TO_PTR(OSIoMesg, ctx->r5);
|
||||
uint32_t direction = ctx->r6;
|
||||
|
@ -182,7 +182,7 @@ extern "C" void osEPiStartDma_recomp(uint8_t* restrict rdram, recomp_context* re
|
|||
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);
|
||||
uint32_t devAddr = handle->baseAddress | ctx->r5;
|
||||
gpr dramAddr = ctx->r6;
|
||||
|
@ -199,10 +199,10 @@ extern "C" void osEPiReadIo_recomp(uint8_t * restrict rdram, recomp_context * re
|
|||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -3,125 +3,125 @@
|
|||
#include "../portultra/multilibultra.hpp"
|
||||
#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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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,
|
||||
(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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
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) {
|
||||
extern "C" void osSetTimer_recomp(uint8_t * rdram, recomp_context * ctx) {
|
||||
uint64_t countdown = ((uint64_t)(ctx->r6) << 32) | ((ctx->r7) & 0xFFFFFFFFu);
|
||||
uint64_t interval = load_doubleword(rdram, ctx->r29, 0x10);
|
||||
ctx->r2 = osSetTimer(rdram, (int32_t)ctx->r4, countdown, interval, (int32_t)MEM_W(0x18, ctx->r29), (OSMesg)MEM_W(0x1C, ctx->r29));
|
||||
}
|
||||
|
||||
extern "C" void osStopTimer_recomp(uint8_t * 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
//
|
||||
// // 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
|
||||
//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");
|
||||
// std::quick_exit(EXIT_FAILURE);
|
||||
//}
|
||||
|
|
|
@ -3,31 +3,31 @@
|
|||
#include "recomp.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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
size_t size = ctx->r5;
|
||||
u32 type = (u32)ctx->r6;
|
||||
|
@ -43,7 +43,7 @@ extern "C" void __osRdbSend_recomp(uint8_t * restrict rdram, recomp_context * re
|
|||
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
|
||||
static std::vector<char> print_buffer;
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ constexpr uint32_t byteswap(uint32_t val) {
|
|||
}
|
||||
#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 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;
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ std::unique_ptr<uint8_t[]> rom;
|
|||
size_t rom_size;
|
||||
|
||||
// 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();
|
||||
const char* get_rom_name();
|
||||
void init_overlays();
|
||||
|
|
|
@ -91,7 +91,7 @@ struct RSP {
|
|||
auto set(u32 index, bool value) -> bool { return u16(index) = 0 - value, value; }
|
||||
|
||||
//vu-registers.cpp
|
||||
auto operator()(u32 index) const -> r128;
|
||||
inline auto operator()(u32 index) const -> r128;
|
||||
};
|
||||
using cr128 = const r128;
|
||||
|
||||
|
@ -109,91 +109,91 @@ struct RSP {
|
|||
static constexpr r128 zero{0};
|
||||
static constexpr r128 invert{(uint64_t)-1, (uint64_t)-1};
|
||||
|
||||
auto accumulatorGet(u32 index) const -> u64;
|
||||
auto accumulatorSet(u32 index, u64 value) -> void;
|
||||
auto accumulatorSaturate(u32 index, bool slice, u16 negative, u16 positive) const -> u16;
|
||||
inline auto accumulatorGet(u32 index) const -> u64;
|
||||
inline auto accumulatorSet(u32 index, u64 value) -> void;
|
||||
inline auto accumulatorSaturate(u32 index, bool slice, u16 negative, u16 positive) const -> u16;
|
||||
|
||||
auto CFC2(r32& rt, u8 rd) -> void;
|
||||
auto CTC2(cr32& rt, u8 rd) -> void;
|
||||
template<u8 e> auto LBV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto LDV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto LFV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto LHV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto LLV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto LPV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto LQV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto LRV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto LSV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto LTV(u8 vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto LUV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto LWV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto MFC2(r32& rt, cr128& vs) -> void;
|
||||
template<u8 e> auto MTC2(cr32& rt, r128& vs) -> void;
|
||||
template<u8 e> auto SBV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto SDV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto SFV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto SHV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto SLV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto SPV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto SQV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto SRV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto SSV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto STV(u8 vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto SUV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto SWV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> auto VABS(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VADD(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VADDC(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VAND(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VCH(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VCL(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VCR(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VEQ(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VGE(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VLT(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
inline auto CFC2(r32& rt, u8 rd) -> void;
|
||||
inline auto CTC2(cr32& rt, u8 rd) -> void;
|
||||
template<u8 e> inline auto LBV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto LDV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto LFV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto LHV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto LLV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto LPV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto LQV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto LRV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto LSV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto LTV(u8 vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto LUV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto LWV(r128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto MFC2(r32& rt, cr128& vs) -> void;
|
||||
template<u8 e> inline auto MTC2(cr32& rt, r128& vs) -> void;
|
||||
template<u8 e> inline auto SBV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto SDV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto SFV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto SHV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto SLV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto SPV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto SQV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto SRV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto SSV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto STV(u8 vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto SUV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto SWV(cr128& vt, cr32& rs, s8 imm) -> void;
|
||||
template<u8 e> inline auto VABS(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VADD(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VADDC(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VAND(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VCH(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VCL(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VCR(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VEQ(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VGE(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VLT(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<bool U, u8 e>
|
||||
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> auto VMACU(r128& vd, cr128& vs, cr128& vt) -> void { VMACF<1, e>(vd, vs, vt); }
|
||||
auto VMACQ(r128& vd) -> void;
|
||||
template<u8 e> auto VMADH(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VMADL(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VMADM(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VMADN(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VMOV(r128& vd, u8 de, cr128& vt) -> void;
|
||||
template<u8 e> auto VMRG(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VMUDH(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VMUDL(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VMUDM(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VMUDN(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
inline auto VMACF(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VMACF(r128& vd, cr128& vs, cr128& vt) -> void { VMACF<0, e>(vd, vs, vt); }
|
||||
template<u8 e> inline auto VMACU(r128& vd, cr128& vs, cr128& vt) -> void { VMACF<1, e>(vd, vs, vt); }
|
||||
inline auto VMACQ(r128& vd) -> void;
|
||||
template<u8 e> inline auto VMADH(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VMADL(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VMADM(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VMADN(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VMOV(r128& vd, u8 de, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VMRG(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VMUDH(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VMUDL(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VMUDM(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VMUDN(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<bool U, u8 e>
|
||||
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> 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> auto VNAND(r128& rd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VNE(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
auto VNOP() -> void;
|
||||
template<u8 e> auto VNOR(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VNXOR(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VOR(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
inline auto VMULF(r128& rd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VMULF(r128& rd, cr128& vs, cr128& vt) -> void { VMULF<0, e>(rd, vs, vt); }
|
||||
template<u8 e> inline auto VMULU(r128& rd, cr128& vs, cr128& vt) -> void { VMULF<1, e>(rd, vs, vt); }
|
||||
template<u8 e> inline auto VMULQ(r128& rd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VNAND(r128& rd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VNE(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
inline auto VNOP() -> void;
|
||||
template<u8 e> inline auto VNOR(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VNXOR(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VOR(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<bool L, u8 e>
|
||||
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> 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;
|
||||
inline auto VRCP(r128& vd, u8 de, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VRCP(r128& vd, u8 de, cr128& vt) -> void { VRCP<0, e>(vd, de, vt); }
|
||||
template<u8 e> inline auto VRCPL(r128& vd, u8 de, cr128& vt) -> void { VRCP<1, e>(vd, de, vt); }
|
||||
template<u8 e> inline auto VRCPH(r128& vd, u8 de, cr128& vt) -> void;
|
||||
template<bool D, u8 e>
|
||||
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> auto VRNDP(r128& vd, u8 vs, cr128& vt) -> void { VRND<1, e>(vd, vs, vt); }
|
||||
inline auto VRND(r128& vd, u8 vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VRNDN(r128& vd, u8 vs, cr128& vt) -> void { VRND<0, e>(vd, vs, vt); }
|
||||
template<u8 e> inline auto VRNDP(r128& vd, u8 vs, cr128& vt) -> void { VRND<1, e>(vd, vs, vt); }
|
||||
template<bool L, u8 e>
|
||||
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> 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> auto VSAR(r128& vd, cr128& vs) -> void;
|
||||
template<u8 e> auto VSUB(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VSUBC(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VXOR(r128& rd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> auto VZERO(r128& rd, cr128& vs, cr128& vt) -> void;
|
||||
inline auto VRSQ(r128& vd, u8 de, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VRSQ(r128& vd, u8 de, cr128& vt) -> void { VRSQ<0, e>(vd, de, vt); }
|
||||
template<u8 e> inline auto VRSQL(r128& vd, u8 de, cr128& vt) -> void { VRSQ<1, e>(vd, de, vt); }
|
||||
template<u8 e> inline auto VRSQH(r128& vd, u8 de, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VSAR(r128& vd, cr128& vs) -> void;
|
||||
template<u8 e> inline auto VSUB(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VSUBC(r128& vd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VXOR(r128& rd, cr128& vs, cr128& vt) -> void;
|
||||
template<u8 e> inline auto VZERO(r128& rd, cr128& vs, cr128& vt) -> void;
|
||||
};
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
#include "../portultra/multilibultra.hpp"
|
||||
#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
|
||||
}
|
||||
|
||||
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);
|
||||
OSTask* task = TO_PTR(OSTask, ctx->r4);
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -1,38 +1,38 @@
|
|||
#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* 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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
extern "C" void osViSetMode_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {
|
||||
extern "C" void osViSetMode_recomp(uint8_t* rdram, recomp_context* ctx) {
|
||||
;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue