diff --git a/src/nba/include/nba/config.hpp b/src/nba/include/nba/config.hpp index 02e63cfa3..1dbcd7e0d 100644 --- a/src/nba/include/nba/config.hpp +++ b/src/nba/include/nba/config.hpp @@ -26,7 +26,8 @@ struct Config { FLASH_64, FLASH_128, EEPROM_4, - EEPROM_64 + EEPROM_64, + EEPROM_DETECT // for internal use }; struct Audio { diff --git a/src/nba/include/nba/rom/backup/eeprom.hpp b/src/nba/include/nba/rom/backup/eeprom.hpp index 37d2937fc..1b71ca6c3 100644 --- a/src/nba/include/nba/rom/backup/eeprom.hpp +++ b/src/nba/include/nba/rom/backup/eeprom.hpp @@ -16,7 +16,8 @@ namespace nba { struct EEPROM : Backup { enum Size { SIZE_4K = 0, - SIZE_64K = 1 + SIZE_64K = 1, + DETECT = 2 }; EEPROM(std::string const& save_path, Size size_hint); @@ -28,6 +29,8 @@ struct EEPROM : Backup { void LoadState(SaveState const& state) final; void CopyState(SaveState& state) final; + void SetSizeHint(Size size); + private: enum State { STATE_ACCEPT_COMMAND = 1 << 0, @@ -50,6 +53,8 @@ struct EEPROM : Backup { int address; u64 serial_buffer; int transmitted_bits; + + bool detect_size; }; } // namespace nba diff --git a/src/nba/include/nba/rom/rom.hpp b/src/nba/include/nba/rom/rom.hpp index 0f9bfef7d..0c274c3b4 100644 --- a/src/nba/include/nba/rom/rom.hpp +++ b/src/nba/include/nba/rom/rom.hpp @@ -106,6 +106,12 @@ struct ROM { } } + void SetEEPROMSizeHint(EEPROM::Size size) { + if (backup_eeprom) { + ((EEPROM*)backup_eeprom.get())->SetSizeHint(size); + } + } + auto ALWAYS_INLINE ReadROM16(u32 address) -> u16 { address &= 0x01FF'FFFE; diff --git a/src/nba/src/hw/dma/dma.cpp b/src/nba/src/hw/dma/dma.cpp index 850b38587..8bb07a3c7 100644 --- a/src/nba/src/hw/dma/dma.cpp +++ b/src/nba/src/hw/dma/dma.cpp @@ -151,13 +151,13 @@ bool DMA::HasVideoTransferDMA() { } void DMA::Run() { - memory.Idle(); + bus.Idle(); do { RunChannel(); } while (IsRunning()); - memory.Idle(); + bus.Idle(); } void DMA::RunChannel() { @@ -203,7 +203,7 @@ void DMA::RunChannel() { u16 value; if (likely(src_addr >= 0x02000000)) { - value = memory.ReadHalf(src_addr, access_src); + value = bus.ReadHalf(src_addr, access_src); channel.latch.bus = (value << 16) | value; latch = channel.latch.bus; } else { @@ -212,19 +212,19 @@ void DMA::RunChannel() { } else { value = channel.latch.bus; } - memory.Idle(); + bus.Idle(); } - memory.WriteHalf(dst_addr, value, access_dst); + bus.WriteHalf(dst_addr, value, access_dst); } else { if (likely(src_addr >= 0x02000000)) { - channel.latch.bus = memory.ReadWord(src_addr, access_src); + channel.latch.bus = bus.ReadWord(src_addr, access_src); latch = channel.latch.bus; } else { - memory.Idle(); + bus.Idle(); } - memory.WriteWord(dst_addr, channel.latch.bus, access_dst); + bus.WriteWord(dst_addr, channel.latch.bus, access_dst); } channel.latch.src_addr += src_modify; @@ -374,6 +374,21 @@ void DMA::OnChannelWritten(Channel& channel, bool enable_old) { } else { AddChannelToDMASet(channel); } + + /* Try to auto-detect EEPROM size from the first EEPROM DMA transfer, + * since we cannot always determine the size at load time. + */ + if (channel.dst_addr >= 0x0D000000) { + int length = channel.length; + + if (length == 9 || length == 73) { + bus.memory.rom.SetEEPROMSizeHint(EEPROM::Size::SIZE_4K); + } + + if (length == 17 || length == 81) { + bus.memory.rom.SetEEPROMSizeHint(EEPROM::Size::SIZE_64K); + } + } } } else { // DMA enable bit: 1 -> 1 (remains set) diff --git a/src/nba/src/hw/dma/dma.hpp b/src/nba/src/hw/dma/dma.hpp index e281f2a22..2b447d0ac 100644 --- a/src/nba/src/hw/dma/dma.hpp +++ b/src/nba/src/hw/dma/dma.hpp @@ -19,8 +19,8 @@ namespace nba::core { struct Bus; struct DMA { - DMA(Bus& memory, IRQ& irq, Scheduler& scheduler) - : memory(memory) + DMA(Bus& bus, IRQ& irq, Scheduler& scheduler) + : bus(bus) , irq(irq) , scheduler(scheduler) { Reset(); @@ -117,7 +117,7 @@ struct DMA { void RemoveChannelFromDMASets(Channel& channel); void RunChannel(); - Bus& memory; + Bus& bus; IRQ& irq; Scheduler& scheduler; diff --git a/src/nba/src/hw/rom/backup/eeprom.cpp b/src/nba/src/hw/rom/backup/eeprom.cpp index 0bfff715f..e7e1a5f6a 100644 --- a/src/nba/src/hw/rom/backup/eeprom.cpp +++ b/src/nba/src/hw/rom/backup/eeprom.cpp @@ -25,9 +25,17 @@ void EEPROM::Reset() { address = 0; ResetSerialBuffer(); + if (size == DETECT) { + size = SIZE_64K; // default to 8 KiB size + detect_size = true; + } else { + detect_size = false; + } + int bytes = g_save_size[size]; - file = BackupFile::OpenOrCreate(save_path, { 512, 8192 }, bytes); + file = BackupFile::OpenOrCreate(save_path, {512, 8192}, bytes); + if (bytes == g_save_size[0]) { size = SIZE_4K; } else { @@ -127,4 +135,17 @@ void EEPROM::Write(u32 address, u8 value) { } } +void EEPROM::SetSizeHint(Size size) { + if (detect_size) { + int bytes = g_save_size[size]; + + this->size = size; + detect_size = false; + + if (file->Size() != bytes) { + file = BackupFile::OpenOrCreate(save_path, {(size_t)bytes}, bytes); + } + } +} + } // namespace nba diff --git a/src/platform/core/src/loader/rom.cpp b/src/platform/core/src/loader/rom.cpp index 726582b8b..ef326a0ad 100644 --- a/src/platform/core/src/loader/rom.cpp +++ b/src/platform/core/src/loader/rom.cpp @@ -192,11 +192,11 @@ auto ROMLoader::GetBackupType( std::vector& file_data ) -> BackupType { static constexpr std::pair signatures[6] { - { "EEPROM_V", BackupType::EEPROM_64 }, - { "SRAM_V", BackupType::SRAM }, - { "SRAM_F_V", BackupType::SRAM }, - { "FLASH_V", BackupType::FLASH_64 }, - { "FLASH512_V", BackupType::FLASH_64 }, + { "EEPROM_V", BackupType::EEPROM_DETECT }, + { "SRAM_V", BackupType::SRAM }, + { "SRAM_F_V", BackupType::SRAM }, + { "FLASH_V", BackupType::FLASH_64 }, + { "FLASH512_V", BackupType::FLASH_64 }, { "FLASH1M_V", BackupType::FLASH_128 } }; @@ -219,21 +219,12 @@ auto ROMLoader::CreateBackup( BackupType backup_type ) -> std::unique_ptr { switch (backup_type) { - case BackupType::SRAM: { - return std::make_unique(save_path); - } - case BackupType::FLASH_64: { - return std::make_unique(save_path, FLASH::SIZE_64K); - } - case BackupType::FLASH_128: { - return std::make_unique(save_path, FLASH::SIZE_128K); - } - case BackupType::EEPROM_4: { - return std::make_unique(save_path, EEPROM::SIZE_4K); - } - case BackupType::EEPROM_64: { - return std::make_unique(save_path, EEPROM::SIZE_64K); - } + case BackupType::SRAM: return std::make_unique(save_path); + case BackupType::FLASH_64: return std::make_unique(save_path, FLASH::SIZE_64K); + case BackupType::FLASH_128: return std::make_unique(save_path, FLASH::SIZE_128K); + case BackupType::EEPROM_4: return std::make_unique(save_path, EEPROM::SIZE_4K); + case BackupType::EEPROM_64: return std::make_unique(save_path, EEPROM::SIZE_64K); + case BackupType::EEPROM_DETECT: return std::make_unique(save_path, EEPROM::DETECT); } return {}; diff --git a/src/platform/qt/src/widget/main_window.cpp b/src/platform/qt/src/widget/main_window.cpp index b3e0e42f7..4eb5f2596 100644 --- a/src/platform/qt/src/widget/main_window.cpp +++ b/src/platform/qt/src/widget/main_window.cpp @@ -467,6 +467,11 @@ void MainWindow::PromptUserForReset() { box.setDefaultButton(QMessageBox::No); if (box.exec() == QMessageBox::Yes) { + // Reload the ROM in case its config (e.g. save type or GPIO) has changed: + if (game_loaded) { + LoadROM(game_path); + } + Reset(); } }