Added MM aspMain parameters to rsp recomp, added voice and flash to special function lists

This commit is contained in:
Mr-Wiseguy 2023-02-19 22:43:08 -05:00
parent 5c5f6a51ad
commit 52644095f0
3 changed files with 144 additions and 39 deletions

View file

@ -510,6 +510,7 @@ void write_indirect_jumps(std::ofstream& output_file, const BranchTargets& branc
}
// TODO de-hardcode these
// OoT njpgdspMain
//constexpr size_t rsp_text_offset = 0xB8BAD0;
//constexpr size_t rsp_text_size = 0xAF0;
//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";
//const std::vector<uint32_t> extra_indirect_branch_targets{};
constexpr size_t rsp_text_offset = 0xB89260;
constexpr size_t rsp_text_size = 0xFB0;
// OoT aspMain
//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;
std::string rom_file_path = "../test/oot_mq_debug.z64";
std::string output_file_path = "../test/rsp/aspMain.cpp";
std::string rom_file_path = "../../MMRecomp/mm.us.rev1.z64"; // uncompressed rom!
std::string output_file_path = "../../MMRecomp/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 };
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
inline uint32_t byteswap(uint32_t val) {
@ -578,8 +591,8 @@ int main() {
// Open output file and write beginning
std::ofstream output_file(output_file_path);
fmt::print(output_file,
"#include \"../src/rsp.h\"\n"
"#include \"../src/rsp_vu_impl.h\"\n"
"#include \"rsp.h\"\n"
"#include \"rsp_vu_impl.h\"\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 r8 = 0, r9 = 0, r10 = 0, r11 = 0, r12 = 0, r13 = 0, r14 = 0, r15 = 0;\n"

View file

@ -76,6 +76,20 @@ std::unordered_set<std::string> reimplemented_funcs{
"osPiGetStatus",
"osEPiRawStartDma",
"osEPiReadIo",
// Flash saving functions
"osFlashInit",
"osFlashReadStatus",
"osFlashReadId",
"osFlashClearStatus",
"osFlashAllErase",
"osFlashAllEraseThrough",
"osFlashSectorErase",
"osFlashSectorEraseThrough",
"osFlashCheckEraseEnd",
"osFlashWriteBuffer",
"osFlashWriteArray",
"osFlashReadArray",
"osFlashChange",
// Threading functions
"osCreateThread",
"osStartThread",
@ -94,6 +108,16 @@ std::unordered_set<std::string> reimplemented_funcs{
"osGetTime",
"osSetTimer",
"osStopTimer",
// Voice functions
"osVoiceSetWord",
"osVoiceCheckWord",
"osVoiceStopReadData",
"osVoiceInit",
"osVoiceMaskDictionary",
"osVoiceStartReadData",
"osVoiceControlGain",
"osVoiceGetReadData",
"osVoiceClearDictionary",
// interrupt functions
"osSetIntMask",
"__osDisableInt",
@ -194,6 +218,7 @@ std::unordered_set<std::string> ignored_funcs {
"__osContGetInitData",
"__osContRamRead",
"__osContRamWrite",
"__osContChannelReset",
// EEPROM functions
"osEepromLongRead",
"osEepromLongWrite",
@ -286,6 +311,20 @@ std::unordered_set<std::string> ignored_funcs {
"__osLeoAbnormalResume",
"__osLeoInterrupt",
"__osLeoResume",
// Flash saving functions
"osFlashInit",
"osFlashReadStatus",
"osFlashReadId",
"osFlashClearStatus",
"osFlashAllErase",
"osFlashAllEraseThrough",
"osFlashSectorErase",
"osFlashSectorEraseThrough",
"osFlashCheckEraseEnd",
"osFlashWriteBuffer",
"osFlashWriteArray",
"osFlashReadArray",
"osFlashChange",
// Threading functions
"osCreateThread",
"osStartThread",
@ -311,6 +350,26 @@ std::unordered_set<std::string> ignored_funcs {
"__osTimerInterrupt",
"__osTimerServicesInit",
"__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
"__osExceptionPreamble",
"__osException",
@ -547,7 +606,11 @@ bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, EL
}
// 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;
size = 0x50; // dummy size for entrypoints, should cover them all
name = "recomp_entrypoint";
@ -638,6 +701,20 @@ struct SegmentEntry {
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* symtab_section = nullptr;
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];
segments[segment_index].data_offset = segment.get_offset();
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
std::sort(segments.begin(), segments.end(),
[](const SegmentEntry& lhs, const SegmentEntry& rhs) {
return lhs.data_offset < rhs.data_offset;
}
);
//// Sort the segments by physical address
//std::sort(segments.begin(), segments.end(),
// [](const SegmentEntry& lhs, const SegmentEntry& rhs) {
// return lhs.data_offset < rhs.data_offset;
// }
//);
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),
// find this section's rom address and copy it into the rom
if (type != ELFIO::SHT_NOBITS && section->get_flags() & ELFIO::SHF_ALLOC) {
// 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(),
[](ELFIO::Elf64_Off section_offset, const SegmentEntry& segment) {
return section_offset < segment.data_offset;
}
);
if (segment_it == segments.begin()) {
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
//auto segment_it = std::upper_bound(segments.begin(), segments.end(), section->get_offset(),
// [](ELFIO::Elf64_Off section_offset, const SegmentEntry& segment) {
// return section_offset < segment.data_offset;
// }
//);
//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());
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;
}
const SegmentEntry& segment = segments[segment_index.value()];
// 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);
// 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) {
if (argc < 3 || argc > 4) {
fmt::print("Usage: {} [input elf file] [entrypoint RAM address] [relocatable sections list file (optional)]\n", argv[0]);
if (argc < 4 || argc > 5) {
fmt::print("Usage: {} [input elf file] [entrypoint RAM address] [output path] [relocatable sections list file (optional)]\n", argv[0]);
std::exit(EXIT_SUCCESS);
}
@ -913,14 +996,19 @@ int main(int argc, char** argv) {
std::unordered_set<std::string> relocatable_sections{};
if (argc == 4) {
if (!read_list_file(argv[3], relocatable_sections)) {
exit_failure("Failed to load the relocatable section list file: " + std::string(argv[3]) + "\n");
if (argc == 5) {
if (!read_list_file(argv[4], relocatable_sections)) {
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] };
if (!output_dir.ends_with('/')) {
output_dir += "/";
}
if (!elf_file.load(elf_name)) {
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());
std::ofstream lookup_file{ "test/funcs/lookup.cpp" };
std::ofstream func_header_file{ "test/funcs/funcs.h" };
std::ofstream lookup_file{ output_dir + "lookup.cpp" };
std::ofstream func_header_file{ output_dir + "funcs.h" };
fmt::print(lookup_file,
//"#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::string output_dir = "test/funcs/";
fmt::print("Working dir: {}\n", std::filesystem::current_path().string());
//#pragma omp parallel for
for (size_t i = 0; i < context.functions.size(); i++) {

View file

@ -974,6 +974,10 @@ bool RecompPort::recompile_function(const RecompPort::Context& context, const Re
// Open the output file and write the file header
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,
"#include \"recomp.h\"\n"
"#include \"disable_warnings.h\"\n"