#include "app/emu/memory/memory.h" #include "imgui/imgui.h" #include #include #include #include #include "app/emu/debug/log.h" namespace yaze { namespace app { namespace emu { namespace memory { void MemoryImpl::Initialize(const std::vector& romData, bool verbose) { verbose_ = verbose; type_ = 1; auto location = 0x7FC0; // GetHeaderOffset(); romSize = 0x400 << romData[location + 0x17]; sramSize = 0x400 << romData[location + 0x18]; rom_.resize(romSize); // Copy memory into rom_ for (size_t i = 0; i < romSize; i++) { rom_[i] = romData[i]; } ram_.resize(sramSize); for (size_t i = 0; i < sramSize; i++) { ram_[i] = 0; } // Clear memory memory_.resize(0x1000000); // 16 MB std::fill(memory_.begin(), memory_.end(), 0); // Load ROM data into memory based on LoROM mapping size_t romSize = romData.size(); size_t romAddress = 0; const size_t ROM_CHUNK_SIZE = 0x8000; // 32 KB for (size_t bank = 0x00; bank <= 0x3F; ++bank) { for (size_t offset = 0x8000; offset <= 0xFFFF; offset += ROM_CHUNK_SIZE) { if (romAddress < romSize) { std::copy(romData.begin() + romAddress, romData.begin() + romAddress + ROM_CHUNK_SIZE, memory_.begin() + (bank << 16) + offset); romAddress += ROM_CHUNK_SIZE; } } } } memory::RomInfo MemoryImpl::ReadRomHeader() { memory::RomInfo romInfo; uint32_t offset = GetHeaderOffset(); // Read cartridge title char title[22]; for (int i = 0; i < 21; ++i) { title[i] = ReadByte(offset + i); } title[21] = '\0'; // Null-terminate the string romInfo.title = std::string(title); // Read ROM speed and memory map mode uint8_t romSpeedAndMapMode = ReadByte(offset + 0x15); romInfo.romSpeed = (memory::RomSpeed)(romSpeedAndMapMode & 0x07); romInfo.bankSize = (memory::BankSize)((romSpeedAndMapMode >> 5) & 0x01); // Read ROM type romInfo.romType = (memory::RomType)ReadByte(offset + 0x16); // Read ROM size romInfo.romSize = (memory::RomSize)ReadByte(offset + 0x17); // Read RAM size romInfo.sramSize = (memory::SramSize)ReadByte(offset + 0x18); // Read country code romInfo.countryCode = (memory::CountryCode)ReadByte(offset + 0x19); // Read license romInfo.license = (memory::License)ReadByte(offset + 0x1A); // Read ROM version romInfo.version = ReadByte(offset + 0x1B); // Read checksum complement romInfo.checksumComplement = ReadWord(offset + 0x1E); // Read checksum romInfo.checksum = ReadWord(offset + 0x1C); // Read NMI VBL vector romInfo.nmiVblVector = ReadWord(offset + 0x3E); // Read reset vector romInfo.resetVector = ReadWord(offset + 0x3C); return romInfo; } uint8_t MemoryImpl::cart_read(uint8_t bank, uint16_t adr) { switch (type_) { case 0: return open_bus_; case 1: return cart_readLorom(bank, adr); case 2: return cart_readHirom(bank, adr); case 3: return cart_readExHirom(bank, adr); } return open_bus_; } void MemoryImpl::cart_write(uint8_t bank, uint16_t adr, uint8_t val) { switch (type_) { case 0: break; case 1: cart_writeLorom(bank, adr, val); break; case 2: cart_writeHirom(bank, adr, val); break; case 3: cart_writeHirom(bank, adr, val); break; } } uint8_t MemoryImpl::cart_readLorom(uint8_t bank, uint16_t adr) { if (((bank >= 0x70 && bank < 0x7e) || bank >= 0xf0) && adr < 0x8000 && sramSize > 0) { // banks 70-7e and f0-ff, adr 0000-7fff return ram_[(((bank & 0xf) << 15) | adr) & (sramSize - 1)]; } bank &= 0x7f; if (adr >= 0x8000 || bank >= 0x40) { // adr 8000-ffff in all banks or all addresses in banks 40-7f and c0-ff return rom_[((bank << 15) | (adr & 0x7fff)) & (romSize - 1)]; } return open_bus_; } void MemoryImpl::cart_writeLorom(uint8_t bank, uint16_t adr, uint8_t val) { if (((bank >= 0x70 && bank < 0x7e) || bank > 0xf0) && adr < 0x8000 && sramSize > 0) { // banks 70-7e and f0-ff, adr 0000-7fff ram_[(((bank & 0xf) << 15) | adr) & (sramSize - 1)] = val; } } uint8_t MemoryImpl::cart_readHirom(uint8_t bank, uint16_t adr) { bank &= 0x7f; if (bank < 0x40 && adr >= 0x6000 && adr < 0x8000 && sramSize > 0) { // banks 00-3f and 80-bf, adr 6000-7fff return ram_[(((bank & 0x3f) << 13) | (adr & 0x1fff)) & (sramSize - 1)]; } if (adr >= 0x8000 || bank >= 0x40) { // adr 8000-ffff in all banks or all addresses in banks 40-7f and c0-ff return rom_[(((bank & 0x3f) << 16) | adr) & (romSize - 1)]; } return open_bus_; } uint8_t MemoryImpl::cart_readExHirom(uint8_t bank, uint16_t adr) { if ((bank & 0x7f) < 0x40 && adr >= 0x6000 && adr < 0x8000 && sramSize > 0) { // banks 00-3f and 80-bf, adr 6000-7fff return ram_[(((bank & 0x3f) << 13) | (adr & 0x1fff)) & (sramSize - 1)]; } bool secondHalf = bank < 0x80; bank &= 0x7f; if (adr >= 0x8000 || bank >= 0x40) { // adr 8000-ffff in all banks or all addresses in banks 40-7f and c0-ff return rom_[(((bank & 0x3f) << 16) | (secondHalf ? 0x400000 : 0) | adr) & (romSize - 1)]; } return open_bus_; } void MemoryImpl::cart_writeHirom(uint8_t bank, uint16_t adr, uint8_t val) { bank &= 0x7f; if (bank < 0x40 && adr >= 0x6000 && adr < 0x8000 && sramSize > 0) { // banks 00-3f and 80-bf, adr 6000-7fff ram_[(((bank & 0x3f) << 13) | (adr & 0x1fff)) & (sramSize - 1)] = val; } } uint32_t MemoryImpl::GetMappedAddress(uint32_t address) const { uint8_t bank = address >> 16; uint32_t offset = address & 0xFFFF; if (bank <= 0x3F) { if (address <= 0x1FFF) { return (0x7E << 16) + offset; // Shadow RAM } else if (address <= 0x5FFF) { return (bank << 16) + (offset - 0x2000) + 0x2000; // Hardware Registers } else if (address <= 0x7FFF) { return offset - 0x6000 + 0x6000; // Expansion RAM } else { // Return lorom mapping return (bank << 16) + (offset - 0x8000) + 0x8000; // ROM } } else if (bank == 0x7D) { return offset + 0x7D0000; // SRAM } else if (bank == 0x7E || bank == 0x7F) { return offset + 0x7E0000; // System RAM } else if (bank >= 0x80) { // Handle HiROM and mirrored areas } return address; // Return the original address if no mapping is defined } void DrawSnesMemoryMapping(const MemoryImpl& memory) { // Using those as a base value to create width/height that are factor of the // size of our font const float TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x; const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing(); const char* column_names[] = { "Offset", "0x00", "0x01", "0x02", "0x03", "0x04", "0x05", "0x06", "0x07", "0x08", "0x09", "0x0A", "0x0B", "0x0C", "0x0D", "0x0E", "0x0F", "0x10", "0x11", "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18", "0x19", "0x1A", "0x1B", "0x1C", "0x1D", "0x1E", "0x1F"}; const int columns_count = IM_ARRAYSIZE(column_names); const int rows_count = 16; static ImGuiTableFlags table_flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_Hideable | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_HighlightHoveredColumn; static bool bools[columns_count * rows_count] = {}; static int frozen_cols = 1; static int frozen_rows = 2; ImGui::CheckboxFlags("_ScrollX", &table_flags, ImGuiTableFlags_ScrollX); ImGui::CheckboxFlags("_ScrollY", &table_flags, ImGuiTableFlags_ScrollY); ImGui::CheckboxFlags("_NoBordersInBody", &table_flags, ImGuiTableFlags_NoBordersInBody); ImGui::CheckboxFlags("_HighlightHoveredColumn", &table_flags, ImGuiTableFlags_HighlightHoveredColumn); ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); ImGui::SliderInt("Frozen columns", &frozen_cols, 0, 2); ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); ImGui::SliderInt("Frozen rows", &frozen_rows, 0, 2); if (ImGui::BeginTable("table_angled_headers", columns_count, table_flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 12))) { ImGui::TableSetupColumn( column_names[0], ImGuiTableColumnFlags_NoHide | ImGuiTableColumnFlags_NoReorder); for (int n = 1; n < columns_count; n++) ImGui::TableSetupColumn(column_names[n], ImGuiTableColumnFlags_AngledHeader | ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupScrollFreeze(frozen_cols, frozen_rows); ImGui::TableAngledHeadersRow(); ImGui::TableHeadersRow(); for (int row = 0; row < rows_count; row++) { ImGui::PushID(row); ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); ImGui::AlignTextToFramePadding(); ImGui::Text("Offset 0x%04X", row); for (int column = 1; column < columns_count; column++) if (ImGui::TableSetColumnIndex(column)) { ImGui::PushID(column); ImGui::Checkbox("", &bools[row * columns_count + column]); ImGui::PopID(); } ImGui::PopID(); } ImGui::EndTable(); } } } // namespace memory } // namespace emu } // namespace app } // namespace yaze