Skip to content

Commit

Permalink
Merge pull request #246 from nba-emu/feature/eeprom-size-detection
Browse files Browse the repository at this point in the history
 EEPROM: automatically detect save size (closes #219)
  • Loading branch information
fleroviux committed Aug 13, 2022
2 parents bee187f + a81097f commit 3a43a77
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 34 deletions.
3 changes: 2 additions & 1 deletion src/nba/include/nba/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ struct Config {
FLASH_64,
FLASH_128,
EEPROM_4,
EEPROM_64
EEPROM_64,
EEPROM_DETECT // for internal use
};

struct Audio {
Expand Down
7 changes: 6 additions & 1 deletion src/nba/include/nba/rom/backup/eeprom.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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,
Expand All @@ -50,6 +53,8 @@ struct EEPROM : Backup {
int address;
u64 serial_buffer;
int transmitted_bits;

bool detect_size;
};

} // namespace nba
6 changes: 6 additions & 0 deletions src/nba/include/nba/rom/rom.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
31 changes: 23 additions & 8 deletions src/nba/src/hw/dma/dma.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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 {
Expand All @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
6 changes: 3 additions & 3 deletions src/nba/src/hw/dma/dma.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -117,7 +117,7 @@ struct DMA {
void RemoveChannelFromDMASets(Channel& channel);
void RunChannel();

Bus& memory;
Bus& bus;
IRQ& irq;
Scheduler& scheduler;

Expand Down
23 changes: 22 additions & 1 deletion src/nba/src/hw/rom/backup/eeprom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
31 changes: 11 additions & 20 deletions src/platform/core/src/loader/rom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,11 @@ auto ROMLoader::GetBackupType(
std::vector<u8>& file_data
) -> BackupType {
static constexpr std::pair<std::string_view, BackupType> 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 }
};

Expand All @@ -219,21 +219,12 @@ auto ROMLoader::CreateBackup(
BackupType backup_type
) -> std::unique_ptr<Backup> {
switch (backup_type) {
case BackupType::SRAM: {
return std::make_unique<SRAM>(save_path);
}
case BackupType::FLASH_64: {
return std::make_unique<FLASH>(save_path, FLASH::SIZE_64K);
}
case BackupType::FLASH_128: {
return std::make_unique<FLASH>(save_path, FLASH::SIZE_128K);
}
case BackupType::EEPROM_4: {
return std::make_unique<EEPROM>(save_path, EEPROM::SIZE_4K);
}
case BackupType::EEPROM_64: {
return std::make_unique<EEPROM>(save_path, EEPROM::SIZE_64K);
}
case BackupType::SRAM: return std::make_unique<SRAM>(save_path);
case BackupType::FLASH_64: return std::make_unique<FLASH>(save_path, FLASH::SIZE_64K);
case BackupType::FLASH_128: return std::make_unique<FLASH>(save_path, FLASH::SIZE_128K);
case BackupType::EEPROM_4: return std::make_unique<EEPROM>(save_path, EEPROM::SIZE_4K);
case BackupType::EEPROM_64: return std::make_unique<EEPROM>(save_path, EEPROM::SIZE_64K);
case BackupType::EEPROM_DETECT: return std::make_unique<EEPROM>(save_path, EEPROM::DETECT);
}

return {};
Expand Down
5 changes: 5 additions & 0 deletions src/platform/qt/src/widget/main_window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
Expand Down

0 comments on commit 3a43a77

Please sign in to comment.