mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2025-01-17 22:25:37 +00:00
CDROM: Deliver data interrupt asynchronously
Prevents FMVs locking up when a command is being executed during a sector read.
This commit is contained in:
parent
27674c2dc9
commit
b4f2bf4d3c
|
@ -44,6 +44,7 @@ void CDROM::SoftReset()
|
||||||
m_mode.bits = 0;
|
m_mode.bits = 0;
|
||||||
m_interrupt_enable_register = INTERRUPT_REGISTER_MASK;
|
m_interrupt_enable_register = INTERRUPT_REGISTER_MASK;
|
||||||
m_interrupt_flag_register = 0;
|
m_interrupt_flag_register = 0;
|
||||||
|
m_pending_async_interrupt = 0;
|
||||||
m_pending_location = {};
|
m_pending_location = {};
|
||||||
m_location_pending = false;
|
m_location_pending = false;
|
||||||
m_filter_file_number = 0;
|
m_filter_file_number = 0;
|
||||||
|
@ -67,6 +68,7 @@ void CDROM::SoftReset()
|
||||||
|
|
||||||
m_param_fifo.Clear();
|
m_param_fifo.Clear();
|
||||||
m_response_fifo.Clear();
|
m_response_fifo.Clear();
|
||||||
|
m_async_response_fifo.Clear();
|
||||||
m_data_fifo.Clear();
|
m_data_fifo.Clear();
|
||||||
m_sector_buffer.clear();
|
m_sector_buffer.clear();
|
||||||
|
|
||||||
|
@ -91,6 +93,7 @@ bool CDROM::DoState(StateWrapper& sw)
|
||||||
sw.Do(&m_mode.bits);
|
sw.Do(&m_mode.bits);
|
||||||
sw.Do(&m_interrupt_enable_register);
|
sw.Do(&m_interrupt_enable_register);
|
||||||
sw.Do(&m_interrupt_flag_register);
|
sw.Do(&m_interrupt_flag_register);
|
||||||
|
sw.Do(&m_pending_async_interrupt);
|
||||||
sw.DoPOD(&m_pending_location);
|
sw.DoPOD(&m_pending_location);
|
||||||
sw.Do(&m_location_pending);
|
sw.Do(&m_location_pending);
|
||||||
sw.Do(&m_filter_file_number);
|
sw.Do(&m_filter_file_number);
|
||||||
|
@ -105,6 +108,7 @@ bool CDROM::DoState(StateWrapper& sw)
|
||||||
sw.Do(&m_xa_resample_sixstep);
|
sw.Do(&m_xa_resample_sixstep);
|
||||||
sw.Do(&m_param_fifo);
|
sw.Do(&m_param_fifo);
|
||||||
sw.Do(&m_response_fifo);
|
sw.Do(&m_response_fifo);
|
||||||
|
sw.Do(&m_async_response_fifo);
|
||||||
sw.Do(&m_data_fifo);
|
sw.Do(&m_data_fifo);
|
||||||
sw.Do(&m_sector_buffer);
|
sw.Do(&m_sector_buffer);
|
||||||
|
|
||||||
|
@ -342,12 +346,19 @@ void CDROM::WriteRegister(u32 offset, u8 value)
|
||||||
{
|
{
|
||||||
Log_DebugPrintf("Interrupt flag register <- 0x%02X", value);
|
Log_DebugPrintf("Interrupt flag register <- 0x%02X", value);
|
||||||
m_interrupt_flag_register &= ~(value & INTERRUPT_REGISTER_MASK);
|
m_interrupt_flag_register &= ~(value & INTERRUPT_REGISTER_MASK);
|
||||||
if (m_interrupt_flag_register == 0 && m_command_state == CommandState::WaitForIRQClear)
|
if (m_interrupt_flag_register == 0)
|
||||||
|
{
|
||||||
|
if (m_command_state == CommandState::WaitForIRQClear)
|
||||||
{
|
{
|
||||||
m_system->Synchronize();
|
m_system->Synchronize();
|
||||||
m_command_state = CommandState::WaitForExecute;
|
m_command_state = CommandState::WaitForExecute;
|
||||||
m_system->SetDowncount(m_command_remaining_ticks);
|
m_system->SetDowncount(m_command_remaining_ticks);
|
||||||
}
|
}
|
||||||
|
else if (HasPendingAsyncInterrupt())
|
||||||
|
{
|
||||||
|
DeliverAsyncInterrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Bit 6 clears the parameter FIFO.
|
// Bit 6 clears the parameter FIFO.
|
||||||
if (value & 0x40)
|
if (value & 0x40)
|
||||||
|
@ -403,6 +414,26 @@ void CDROM::SetInterrupt(Interrupt interrupt)
|
||||||
m_interrupt_controller->InterruptRequest(InterruptController::IRQ::CDROM);
|
m_interrupt_controller->InterruptRequest(InterruptController::IRQ::CDROM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CDROM::SetAsyncInterrupt(Interrupt interrupt)
|
||||||
|
{
|
||||||
|
Assert(m_pending_async_interrupt == 0);
|
||||||
|
m_pending_async_interrupt = static_cast<u8>(interrupt);
|
||||||
|
if (!HasPendingInterrupt())
|
||||||
|
DeliverAsyncInterrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDROM::DeliverAsyncInterrupt()
|
||||||
|
{
|
||||||
|
Assert(m_pending_async_interrupt != 0 && !HasPendingInterrupt());
|
||||||
|
Log_DevPrintf("Delivering async interrupt %u", m_pending_async_interrupt);
|
||||||
|
|
||||||
|
m_response_fifo.Clear();
|
||||||
|
m_response_fifo.PushFromQueue(&m_async_response_fifo);
|
||||||
|
m_interrupt_flag_register = m_pending_async_interrupt;
|
||||||
|
m_pending_async_interrupt = 0;
|
||||||
|
m_interrupt_controller->InterruptRequest(InterruptController::IRQ::CDROM);
|
||||||
|
}
|
||||||
|
|
||||||
void CDROM::SendACKAndStat()
|
void CDROM::SendACKAndStat()
|
||||||
{
|
{
|
||||||
m_response_fifo.Push(m_secondary_status.bits);
|
m_response_fifo.Push(m_secondary_status.bits);
|
||||||
|
@ -894,13 +925,9 @@ void CDROM::BeginReading(bool cdda)
|
||||||
|
|
||||||
void CDROM::DoSectorRead()
|
void CDROM::DoSectorRead()
|
||||||
{
|
{
|
||||||
if (HasPendingInterrupt())
|
if (HasPendingAsyncInterrupt())
|
||||||
{
|
{
|
||||||
// can't read with a pending interrupt?
|
Log_WarningPrintf("Data interrupt was not delivered");
|
||||||
Log_WarningPrintf("Missed sector read...");
|
|
||||||
// m_sector_read_remaining_ticks += 10;
|
|
||||||
// m_system->SetDowncount(m_sector_read_remaining_ticks);
|
|
||||||
// return;
|
|
||||||
}
|
}
|
||||||
if (!m_sector_buffer.empty())
|
if (!m_sector_buffer.empty())
|
||||||
{
|
{
|
||||||
|
@ -963,8 +990,8 @@ void CDROM::ProcessDataSector()
|
||||||
|
|
||||||
if (pass_to_cpu)
|
if (pass_to_cpu)
|
||||||
{
|
{
|
||||||
m_response_fifo.Push(m_secondary_status.bits);
|
m_async_response_fifo.Push(m_secondary_status.bits);
|
||||||
SetInterrupt(Interrupt::INT1);
|
SetAsyncInterrupt(Interrupt::INT1);
|
||||||
UpdateStatusRegister();
|
UpdateStatusRegister();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,7 +160,10 @@ private:
|
||||||
void SoftReset();
|
void SoftReset();
|
||||||
|
|
||||||
bool HasPendingInterrupt() const { return m_interrupt_flag_register != 0; }
|
bool HasPendingInterrupt() const { return m_interrupt_flag_register != 0; }
|
||||||
|
bool HasPendingAsyncInterrupt() const { return m_pending_async_interrupt != 0; }
|
||||||
void SetInterrupt(Interrupt interrupt);
|
void SetInterrupt(Interrupt interrupt);
|
||||||
|
void SetAsyncInterrupt(Interrupt interrupt);
|
||||||
|
void DeliverAsyncInterrupt();
|
||||||
void SendACKAndStat();
|
void SendACKAndStat();
|
||||||
void SendErrorResponse(u8 reason = 0x80);
|
void SendErrorResponse(u8 reason = 0x80);
|
||||||
void UpdateStatusRegister();
|
void UpdateStatusRegister();
|
||||||
|
@ -201,6 +204,7 @@ private:
|
||||||
|
|
||||||
u8 m_interrupt_enable_register = INTERRUPT_REGISTER_MASK;
|
u8 m_interrupt_enable_register = INTERRUPT_REGISTER_MASK;
|
||||||
u8 m_interrupt_flag_register = 0;
|
u8 m_interrupt_flag_register = 0;
|
||||||
|
u8 m_pending_async_interrupt = 0;
|
||||||
|
|
||||||
CDImage::Position m_pending_location = {};
|
CDImage::Position m_pending_location = {};
|
||||||
bool m_location_pending = false;
|
bool m_location_pending = false;
|
||||||
|
@ -221,6 +225,7 @@ private:
|
||||||
|
|
||||||
InlineFIFOQueue<u8, PARAM_FIFO_SIZE> m_param_fifo;
|
InlineFIFOQueue<u8, PARAM_FIFO_SIZE> m_param_fifo;
|
||||||
InlineFIFOQueue<u8, RESPONSE_FIFO_SIZE> m_response_fifo;
|
InlineFIFOQueue<u8, RESPONSE_FIFO_SIZE> m_response_fifo;
|
||||||
|
InlineFIFOQueue<u8, RESPONSE_FIFO_SIZE> m_async_response_fifo;
|
||||||
HeapFIFOQueue<u8, DATA_FIFO_SIZE> m_data_fifo;
|
HeapFIFOQueue<u8, DATA_FIFO_SIZE> m_data_fifo;
|
||||||
std::vector<u8> m_sector_buffer;
|
std::vector<u8> m_sector_buffer;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue