Added MM aspMain parameters to rsp recomp, added voice and flash to special function lists
This commit is contained in:
parent
5c5f6a51ad
commit
52644095f0
|
@ -510,6 +510,7 @@ void write_indirect_jumps(std::ofstream& output_file, const BranchTargets& branc
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO de-hardcode these
|
// TODO de-hardcode these
|
||||||
|
// OoT njpgdspMain
|
||||||
//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;
|
||||||
|
@ -518,13 +519,25 @@ void write_indirect_jumps(std::ofstream& output_file, const BranchTargets& branc
|
||||||
//std::string output_function_name = "njpgdspMain";
|
//std::string output_function_name = "njpgdspMain";
|
||||||
//const std::vector<uint32_t> extra_indirect_branch_targets{};
|
//const std::vector<uint32_t> extra_indirect_branch_targets{};
|
||||||
|
|
||||||
constexpr size_t rsp_text_offset = 0xB89260;
|
// OoT aspMain
|
||||||
constexpr size_t rsp_text_size = 0xFB0;
|
//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/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 };
|
||||||
|
|
||||||
|
// MM's njpgdspMain is identical to OoT's
|
||||||
|
|
||||||
|
// MM aspMain
|
||||||
|
constexpr size_t rsp_text_offset = 0xC40FF0;
|
||||||
|
constexpr size_t rsp_text_size = 0x1000;
|
||||||
constexpr size_t rsp_text_address = 0x04001000;
|
constexpr size_t rsp_text_address = 0x04001000;
|
||||||
std::string rom_file_path = "../test/oot_mq_debug.z64";
|
std::string rom_file_path = "../../MMRecomp/mm.us.rev1.z64"; // uncompressed rom!
|
||||||
std::string output_file_path = "../test/rsp/aspMain.cpp";
|
std::string output_file_path = "../../MMRecomp/rsp/aspMain.cpp";
|
||||||
std::string output_function_name = "aspMain";
|
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 };
|
const std::vector<uint32_t> extra_indirect_branch_targets{ 0x1F80, 0x1250, 0x1154, 0x1094, 0x1E0C, 0x1514, 0x1E7C, 0x1C90, 0x1180, 0x1808, 0x11E8, 0x1ADC, 0x1B6C, 0x1194, 0x1EF8, 0x1240, 0x17C0, 0x186C, 0x1A58, 0x18BC, 0x1ABC, 0x1ACC, 0x1A80, 0x1BD4 };
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
inline uint32_t byteswap(uint32_t val) {
|
inline uint32_t byteswap(uint32_t val) {
|
||||||
|
@ -578,8 +591,8 @@ int main() {
|
||||||
// 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,
|
||||||
"#include \"../src/rsp.h\"\n"
|
"#include \"rsp.h\"\n"
|
||||||
"#include \"../src/rsp_vu_impl.h\"\n"
|
"#include \"rsp_vu_impl.h\"\n"
|
||||||
"RspExitReason {}(uint8_t* rdram) {{\n"
|
"RspExitReason {}(uint8_t* rdram) {{\n"
|
||||||
" uint32_t r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0, r7 = 0;\n"
|
" uint32_t r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0, r7 = 0;\n"
|
||||||
" uint32_t r8 = 0, r9 = 0, r10 = 0, r11 = 0, r12 = 0, r13 = 0, r14 = 0, r15 = 0;\n"
|
" uint32_t r8 = 0, r9 = 0, r10 = 0, r11 = 0, r12 = 0, r13 = 0, r14 = 0, r15 = 0;\n"
|
||||||
|
|
152
src/main.cpp
152
src/main.cpp
|
@ -76,6 +76,20 @@ std::unordered_set<std::string> reimplemented_funcs{
|
||||||
"osPiGetStatus",
|
"osPiGetStatus",
|
||||||
"osEPiRawStartDma",
|
"osEPiRawStartDma",
|
||||||
"osEPiReadIo",
|
"osEPiReadIo",
|
||||||
|
// Flash saving functions
|
||||||
|
"osFlashInit",
|
||||||
|
"osFlashReadStatus",
|
||||||
|
"osFlashReadId",
|
||||||
|
"osFlashClearStatus",
|
||||||
|
"osFlashAllErase",
|
||||||
|
"osFlashAllEraseThrough",
|
||||||
|
"osFlashSectorErase",
|
||||||
|
"osFlashSectorEraseThrough",
|
||||||
|
"osFlashCheckEraseEnd",
|
||||||
|
"osFlashWriteBuffer",
|
||||||
|
"osFlashWriteArray",
|
||||||
|
"osFlashReadArray",
|
||||||
|
"osFlashChange",
|
||||||
// Threading functions
|
// Threading functions
|
||||||
"osCreateThread",
|
"osCreateThread",
|
||||||
"osStartThread",
|
"osStartThread",
|
||||||
|
@ -94,6 +108,16 @@ std::unordered_set<std::string> reimplemented_funcs{
|
||||||
"osGetTime",
|
"osGetTime",
|
||||||
"osSetTimer",
|
"osSetTimer",
|
||||||
"osStopTimer",
|
"osStopTimer",
|
||||||
|
// Voice functions
|
||||||
|
"osVoiceSetWord",
|
||||||
|
"osVoiceCheckWord",
|
||||||
|
"osVoiceStopReadData",
|
||||||
|
"osVoiceInit",
|
||||||
|
"osVoiceMaskDictionary",
|
||||||
|
"osVoiceStartReadData",
|
||||||
|
"osVoiceControlGain",
|
||||||
|
"osVoiceGetReadData",
|
||||||
|
"osVoiceClearDictionary",
|
||||||
// interrupt functions
|
// interrupt functions
|
||||||
"osSetIntMask",
|
"osSetIntMask",
|
||||||
"__osDisableInt",
|
"__osDisableInt",
|
||||||
|
@ -194,6 +218,7 @@ std::unordered_set<std::string> ignored_funcs {
|
||||||
"__osContGetInitData",
|
"__osContGetInitData",
|
||||||
"__osContRamRead",
|
"__osContRamRead",
|
||||||
"__osContRamWrite",
|
"__osContRamWrite",
|
||||||
|
"__osContChannelReset",
|
||||||
// EEPROM functions
|
// EEPROM functions
|
||||||
"osEepromLongRead",
|
"osEepromLongRead",
|
||||||
"osEepromLongWrite",
|
"osEepromLongWrite",
|
||||||
|
@ -286,6 +311,20 @@ std::unordered_set<std::string> ignored_funcs {
|
||||||
"__osLeoAbnormalResume",
|
"__osLeoAbnormalResume",
|
||||||
"__osLeoInterrupt",
|
"__osLeoInterrupt",
|
||||||
"__osLeoResume",
|
"__osLeoResume",
|
||||||
|
// Flash saving functions
|
||||||
|
"osFlashInit",
|
||||||
|
"osFlashReadStatus",
|
||||||
|
"osFlashReadId",
|
||||||
|
"osFlashClearStatus",
|
||||||
|
"osFlashAllErase",
|
||||||
|
"osFlashAllEraseThrough",
|
||||||
|
"osFlashSectorErase",
|
||||||
|
"osFlashSectorEraseThrough",
|
||||||
|
"osFlashCheckEraseEnd",
|
||||||
|
"osFlashWriteBuffer",
|
||||||
|
"osFlashWriteArray",
|
||||||
|
"osFlashReadArray",
|
||||||
|
"osFlashChange",
|
||||||
// Threading functions
|
// Threading functions
|
||||||
"osCreateThread",
|
"osCreateThread",
|
||||||
"osStartThread",
|
"osStartThread",
|
||||||
|
@ -311,6 +350,26 @@ std::unordered_set<std::string> ignored_funcs {
|
||||||
"__osTimerInterrupt",
|
"__osTimerInterrupt",
|
||||||
"__osTimerServicesInit",
|
"__osTimerServicesInit",
|
||||||
"__osSetTimerIntr",
|
"__osSetTimerIntr",
|
||||||
|
// Voice functions
|
||||||
|
"osVoiceSetWord",
|
||||||
|
"osVoiceCheckWord",
|
||||||
|
"osVoiceStopReadData",
|
||||||
|
"osVoiceInit",
|
||||||
|
"osVoiceMaskDictionary",
|
||||||
|
"osVoiceStartReadData",
|
||||||
|
"osVoiceControlGain",
|
||||||
|
"osVoiceGetReadData",
|
||||||
|
"osVoiceClearDictionary",
|
||||||
|
"__osVoiceCheckResult",
|
||||||
|
"__osVoiceContRead36",
|
||||||
|
"__osVoiceContWrite20",
|
||||||
|
"__osVoiceContWrite4",
|
||||||
|
"__osVoiceContRead2",
|
||||||
|
"__osVoiceSetADConverter",
|
||||||
|
"__osVoiceContDataCrc",
|
||||||
|
"__osVoiceGetStatus",
|
||||||
|
"corrupted",
|
||||||
|
"corrupted_init",
|
||||||
// exceptasm functions
|
// exceptasm functions
|
||||||
"__osExceptionPreamble",
|
"__osExceptionPreamble",
|
||||||
"__osException",
|
"__osException",
|
||||||
|
@ -547,7 +606,11 @@ bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, EL
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this symbol is the entrypoint
|
// Check if this symbol is the entrypoint
|
||||||
if (value == entrypoint && type == ELFIO::STT_FUNC) {
|
if (value == entrypoint /*&& type == ELFIO::STT_FUNC*/) {
|
||||||
|
if (found_entrypoint_func) {
|
||||||
|
fmt::print(stderr, "Ambiguous entrypoint\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
found_entrypoint_func = true;
|
found_entrypoint_func = true;
|
||||||
size = 0x50; // dummy size for entrypoints, should cover them all
|
size = 0x50; // dummy size for entrypoints, should cover them all
|
||||||
name = "recomp_entrypoint";
|
name = "recomp_entrypoint";
|
||||||
|
@ -638,6 +701,20 @@ struct SegmentEntry {
|
||||||
ELFIO::Elf_Xword memory_size;
|
ELFIO::Elf_Xword memory_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::optional<size_t> get_segment(const std::vector<SegmentEntry>& segments, ELFIO::Elf_Xword section_size, ELFIO::Elf64_Off section_offset) {
|
||||||
|
// A linear search is safest even if the segment list is sorted, as there may be overlapping segments
|
||||||
|
for (size_t i = 0; i < segments.size(); i++) {
|
||||||
|
const auto& segment = segments[i];
|
||||||
|
|
||||||
|
// Check that the section's data in the elf file is within bounds of the segment's data
|
||||||
|
if (section_offset >= segment.data_offset && section_offset + section_size <= segment.data_offset + segment.memory_size) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
ELFIO::section* read_sections(RecompPort::Context& context, const ELFIO::elfio& elf_file) {
|
ELFIO::section* read_sections(RecompPort::Context& context, const ELFIO::elfio& elf_file) {
|
||||||
ELFIO::section* symtab_section = nullptr;
|
ELFIO::section* symtab_section = nullptr;
|
||||||
std::vector<SegmentEntry> segments{};
|
std::vector<SegmentEntry> segments{};
|
||||||
|
@ -648,15 +725,15 @@ ELFIO::section* read_sections(RecompPort::Context& context, const ELFIO::elfio&
|
||||||
const auto& segment = *elf_file.segments[segment_index];
|
const auto& segment = *elf_file.segments[segment_index];
|
||||||
segments[segment_index].data_offset = segment.get_offset();
|
segments[segment_index].data_offset = segment.get_offset();
|
||||||
segments[segment_index].physical_address = segment.get_physical_address();
|
segments[segment_index].physical_address = segment.get_physical_address();
|
||||||
segments[segment_index].memory_size = segment.get_memory_size();
|
segments[segment_index].memory_size = segment.get_file_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort the segments by physical address
|
//// Sort the segments by physical address
|
||||||
std::sort(segments.begin(), segments.end(),
|
//std::sort(segments.begin(), segments.end(),
|
||||||
[](const SegmentEntry& lhs, const SegmentEntry& rhs) {
|
// [](const SegmentEntry& lhs, const SegmentEntry& rhs) {
|
||||||
return lhs.data_offset < rhs.data_offset;
|
// return lhs.data_offset < rhs.data_offset;
|
||||||
}
|
// }
|
||||||
);
|
//);
|
||||||
|
|
||||||
std::unordered_map<std::string, ELFIO::section*> reloc_sections_by_name;
|
std::unordered_map<std::string, ELFIO::section*> reloc_sections_by_name;
|
||||||
|
|
||||||
|
@ -694,25 +771,31 @@ ELFIO::section* read_sections(RecompPort::Context& context, const ELFIO::elfio&
|
||||||
|
|
||||||
// If this section isn't bss (SHT_NOBITS) and ends up in the rom (SHF_ALLOC),
|
// If this section isn't bss (SHT_NOBITS) and ends up in the rom (SHF_ALLOC),
|
||||||
// find this section's rom address and copy it into the rom
|
// find this section's rom address and copy it into the rom
|
||||||
if (type != ELFIO::SHT_NOBITS && section->get_flags() & ELFIO::SHF_ALLOC) {
|
if (type != ELFIO::SHT_NOBITS && section->get_flags() & ELFIO::SHF_ALLOC && section->get_size() != 0) {
|
||||||
// Find the segment this section is in to determine the physical (rom) address of the section
|
//// Find the segment this section is in to determine the physical (rom) address of the section
|
||||||
auto segment_it = std::upper_bound(segments.begin(), segments.end(), section->get_offset(),
|
//auto segment_it = std::upper_bound(segments.begin(), segments.end(), section->get_offset(),
|
||||||
[](ELFIO::Elf64_Off section_offset, const SegmentEntry& segment) {
|
// [](ELFIO::Elf64_Off section_offset, const SegmentEntry& segment) {
|
||||||
return section_offset < segment.data_offset;
|
// return section_offset < segment.data_offset;
|
||||||
}
|
// }
|
||||||
);
|
//);
|
||||||
if (segment_it == segments.begin()) {
|
//if (segment_it == segments.begin()) {
|
||||||
|
// fmt::print(stderr, "Could not find segment that section {} belongs to!\n", section_name.c_str());
|
||||||
|
// return nullptr;
|
||||||
|
//}
|
||||||
|
//// Upper bound returns the iterator after the element we're looking for, so rewind by one
|
||||||
|
//// This is safe because we checked if segment_it was segments.begin() already, which is the minimum value it could be
|
||||||
|
//const SegmentEntry& segment = *(segment_it - 1);
|
||||||
|
//// Check to be sure that the section is actually in this segment
|
||||||
|
//if (section->get_offset() >= segment.data_offset + segment.memory_size) {
|
||||||
|
// fmt::print(stderr, "Section {} out of range of segment at offset 0x{:08X}\n", section_name.c_str(), segment.data_offset);
|
||||||
|
// return nullptr;
|
||||||
|
//}
|
||||||
|
std::optional<size_t> segment_index = get_segment(segments, section_out.size, section->get_offset());
|
||||||
|
if (!segment_index.has_value()) {
|
||||||
fmt::print(stderr, "Could not find segment that section {} belongs to!\n", section_name.c_str());
|
fmt::print(stderr, "Could not find segment that section {} belongs to!\n", section_name.c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
// Upper bound returns the iterator after the element we're looking for, so rewind by one
|
const SegmentEntry& segment = segments[segment_index.value()];
|
||||||
// This is safe because we checked if segment_it was segments.begin() already, which is the minimum value it could be
|
|
||||||
const SegmentEntry& segment = *(segment_it - 1);
|
|
||||||
// Check to be sure that the section is actually in this segment
|
|
||||||
if (section->get_offset() >= segment.data_offset + segment.memory_size) {
|
|
||||||
fmt::print(stderr, "Section {} out of range of segment at offset 0x{:08X}\n", section_name.c_str(), segment.data_offset);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
// Calculate the rom address based on this section's offset into the segment and the segment's rom address
|
// Calculate the rom address based on this section's offset into the segment and the segment's rom address
|
||||||
section_out.rom_addr = segment.physical_address + (section->get_offset() - segment.data_offset);
|
section_out.rom_addr = segment.physical_address + (section->get_offset() - segment.data_offset);
|
||||||
// Resize the output rom if needed to fit this section
|
// Resize the output rom if needed to fit this section
|
||||||
|
@ -895,8 +978,8 @@ bool read_list_file(const char* filename, std::unordered_set<std::string>& entri
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
if (argc < 3 || argc > 4) {
|
if (argc < 4 || argc > 5) {
|
||||||
fmt::print("Usage: {} [input elf file] [entrypoint RAM address] [relocatable sections list file (optional)]\n", argv[0]);
|
fmt::print("Usage: {} [input elf file] [entrypoint RAM address] [output path] [relocatable sections list file (optional)]\n", argv[0]);
|
||||||
std::exit(EXIT_SUCCESS);
|
std::exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -913,14 +996,19 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
std::unordered_set<std::string> relocatable_sections{};
|
std::unordered_set<std::string> relocatable_sections{};
|
||||||
|
|
||||||
if (argc == 4) {
|
if (argc == 5) {
|
||||||
if (!read_list_file(argv[3], relocatable_sections)) {
|
if (!read_list_file(argv[4], relocatable_sections)) {
|
||||||
exit_failure("Failed to load the relocatable section list file: " + std::string(argv[3]) + "\n");
|
exit_failure("Failed to load the relocatable section list file: " + std::string(argv[4]) + "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string output_dir{ argv[3] };
|
||||||
std::string elf_name{ argv[1] };
|
std::string elf_name{ argv[1] };
|
||||||
|
|
||||||
|
if (!output_dir.ends_with('/')) {
|
||||||
|
output_dir += "/";
|
||||||
|
}
|
||||||
|
|
||||||
if (!elf_file.load(elf_name)) {
|
if (!elf_file.load(elf_name)) {
|
||||||
exit_failure("Failed to load provided elf file\n");
|
exit_failure("Failed to load provided elf file\n");
|
||||||
}
|
}
|
||||||
|
@ -962,8 +1050,8 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
fmt::print("Function count: {}\n", context.functions.size());
|
fmt::print("Function count: {}\n", context.functions.size());
|
||||||
|
|
||||||
std::ofstream lookup_file{ "test/funcs/lookup.cpp" };
|
std::ofstream lookup_file{ output_dir + "lookup.cpp" };
|
||||||
std::ofstream func_header_file{ "test/funcs/funcs.h" };
|
std::ofstream func_header_file{ output_dir + "funcs.h" };
|
||||||
|
|
||||||
fmt::print(lookup_file,
|
fmt::print(lookup_file,
|
||||||
//"#include <utility>\n"
|
//"#include <utility>\n"
|
||||||
|
@ -984,7 +1072,7 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
std::vector<std::vector<uint32_t>> static_funcs_by_section{ context.sections.size() };
|
std::vector<std::vector<uint32_t>> static_funcs_by_section{ context.sections.size() };
|
||||||
|
|
||||||
std::string output_dir = "test/funcs/";
|
fmt::print("Working dir: {}\n", std::filesystem::current_path().string());
|
||||||
|
|
||||||
//#pragma omp parallel for
|
//#pragma omp parallel for
|
||||||
for (size_t i = 0; i < context.functions.size(); i++) {
|
for (size_t i = 0; i < context.functions.size(); i++) {
|
||||||
|
|
|
@ -974,6 +974,10 @@ bool RecompPort::recompile_function(const RecompPort::Context& context, const Re
|
||||||
|
|
||||||
// Open the output file and write the file header
|
// Open the output file and write the file header
|
||||||
std::ofstream output_file{ output_path.data() };
|
std::ofstream output_file{ output_path.data() };
|
||||||
|
if (!output_file.good()) {
|
||||||
|
fmt::print(stderr, "Failed to open file for writing: {}\n", output_path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
fmt::print(output_file,
|
fmt::print(output_file,
|
||||||
"#include \"recomp.h\"\n"
|
"#include \"recomp.h\"\n"
|
||||||
"#include \"disable_warnings.h\"\n"
|
"#include \"disable_warnings.h\"\n"
|
||||||
|
|
Loading…
Reference in a new issue