From 859517526784274cab3fb3650a67b5d54231242b Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 9 Jun 2024 19:42:17 +1000 Subject: [PATCH] CDROM: Improve accuracy of sector redelivery on DMA complete Fixes hang in loading in Syphon Filter 2/3. --- src/core/cdrom.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/core/cdrom.cpp b/src/core/cdrom.cpp index 7575cbbd8..5877db1a9 100644 --- a/src/core/cdrom.cpp +++ b/src/core/cdrom.cpp @@ -3381,17 +3381,20 @@ void CDROM::CheckForSectorBufferReadComplete() { sb.position = 0; sb.size = 0; + } - // Redeliver missed sector on DMA/read complete. - // I'm still not sure if this is correct behavior. - SectorBuffer& next_sb = s_sector_buffers[s_current_write_sector_buffer]; - if (next_sb.position == 0 && next_sb.size > 0) - { - DEV_LOG("Sending additional INT1 for missed sector in buffer {}", s_current_write_sector_buffer); - s_current_read_sector_buffer = s_current_write_sector_buffer; - s_async_response_fifo.Push(s_secondary_status.bits); - SetAsyncInterrupt(Interrupt::DataReady); - } + // Redeliver missed sector on DMA/read complete. + // This would be the main loop checking when the DMA is complete, if there's another sector pending. + // Normally, this would happen some time after the DMA actually completes, so we need to put it on a delay. + // Otherwise, if games read the header then data out as two separate transfers (which is typical), they'll + // get the header for one sector, and the header for the next in the second transfer. + SectorBuffer& next_sb = s_sector_buffers[s_current_write_sector_buffer]; + if (next_sb.position == 0 && next_sb.size > 0 && !HasPendingAsyncInterrupt()) + { + DEV_LOG("Sending additional INT1 for missed sector in buffer {}", s_current_write_sector_buffer); + s_async_response_fifo.Push(s_secondary_status.bits); + s_pending_async_interrupt = static_cast(Interrupt::DataReady); + s_async_interrupt_event->Schedule(INTERRUPT_DELAY_CYCLES); } }