From 078a10dcdb14f5dd3137f99a7f3a3f006901182f Mon Sep 17 00:00:00 2001 From: TheLastRar Date: Sun, 13 Oct 2024 16:28:18 +0100 Subject: [PATCH] DEV9: Implement ATA pending interrupts --- pcsx2/DEV9/ATA/ATA.h | 2 ++ pcsx2/DEV9/ATA/ATA_State.cpp | 25 ++++++++++++++++--- pcsx2/DEV9/ATA/Commands/ATA_CmdDMA.cpp | 4 ++- .../ATA/Commands/ATA_CmdExecuteDeviceDiag.cpp | 9 +++++-- pcsx2/DEV9/ATA/Commands/ATA_CmdNoData.cpp | 1 + pcsx2/DEV9/ATA/Commands/ATA_CmdPIOData.cpp | 6 ++++- 6 files changed, 40 insertions(+), 7 deletions(-) diff --git a/pcsx2/DEV9/ATA/ATA.h b/pcsx2/DEV9/ATA/ATA.h index 456e94f1bc..e49d6425a1 100644 --- a/pcsx2/DEV9/ATA/ATA.h +++ b/pcsx2/DEV9/ATA/ATA.h @@ -96,6 +96,8 @@ private: u8 regStatus; //ReadOnly. When read via AlternateStatus pending interrupts are not cleared + bool pendingInterrupt = false; + //Transfer //Write Buffer(s) bool awaitFlush = false; diff --git a/pcsx2/DEV9/ATA/ATA_State.cpp b/pcsx2/DEV9/ATA/ATA_State.cpp index a96444adb2..4207c3a5d9 100644 --- a/pcsx2/DEV9/ATA/ATA_State.cpp +++ b/pcsx2/DEV9/ATA/ATA_State.cpp @@ -380,6 +380,7 @@ u16 ATA::Read(u32 addr, int width) return regSelect; case ATA_R_STATUS: // Clear irqcause + pendingInterrupt = false; dev9.irqcause &= ~ATA_INTR_INTRQ; [[fallthrough]]; case ATA_R_ALT_STATUS: @@ -437,21 +438,38 @@ void ATA::Write(u32 addr, u16 value, int width) regHcyl = static_cast(value); break; case ATA_R_SELECT: + { //DevCon.WriteLn("DEV9: ATA: ATA_R_SELECT %dbit write %x", width, value); + const int oldDev = GetSelectedDevice(); + const int newDev = (value >> 4) & 1; + // Suppress INTRQ when not selected device + if (oldDev == 0 && newDev == 1) + { + dev9.irqcause &= ~ATA_INTR_INTRQ; + } + else if (oldDev == 1 && newDev == 0) + { + if (regControlEnableIRQ && pendingInterrupt) + _DEV9irq(ATA_INTR_INTRQ, 1); + } + regSelect = static_cast(value); - //bus->ifs[0].select = (val & ~0x10) | 0xa0; - //bus->ifs[1].select = (val | 0x10) | 0xa0; break; + } case ATA_R_CONTROL: //DevCon.WriteLn("DEV9: ATA: ATA_R_CONTROL %dbit write %x", width, value); if ((value & 0x2) != 0) { - // Suppress all IRQ + // Suppress INTRQ dev9.irqcause &= ~ATA_INTR_INTRQ; regControlEnableIRQ = false; } else + { + if (GetSelectedDevice() == 0 && regControlEnableIRQ == false && pendingInterrupt) + _DEV9irq(ATA_INTR_INTRQ, 1); regControlEnableIRQ = true; + } if ((value & 0x4) != 0) { @@ -467,6 +485,7 @@ void ATA::Write(u32 addr, u16 value, int width) //DevCon.WriteLn("DEV9: ATA: ATA_R_CMD %dbit write %x", width, value); regCommand = value; regControlHOBRead = false; + pendingInterrupt = false; dev9.irqcause &= ~ATA_INTR_INTRQ; IDE_ExecCmd(value); break; diff --git a/pcsx2/DEV9/ATA/Commands/ATA_CmdDMA.cpp b/pcsx2/DEV9/ATA/Commands/ATA_CmdDMA.cpp index c240e942f7..8b3ace0c03 100644 --- a/pcsx2/DEV9/ATA/Commands/ATA_CmdDMA.cpp +++ b/pcsx2/DEV9/ATA/Commands/ATA_CmdDMA.cpp @@ -23,6 +23,7 @@ void ATA::PostCmdDMADataToHost() dmaReady = false; dev9.irqcause &= ~SPD_INTR_ATA_FIFO_DATA; + pendingInterrupt = true; if (regControlEnableIRQ) _DEV9irq(ATA_INTR_INTRQ, 1); //PCSX2 Will Start DMA @@ -66,8 +67,9 @@ void ATA::PostCmdDMADataFromHost() if (fetWriteCacheEnabled) { regStatus &= ~ATA_STAT_BUSY; + pendingInterrupt = true; if (regControlEnableIRQ) - _DEV9irq(ATA_INTR_INTRQ, 1); //0x6C + _DEV9irq(ATA_INTR_INTRQ, 1); } else awaitFlush = true; diff --git a/pcsx2/DEV9/ATA/Commands/ATA_CmdExecuteDeviceDiag.cpp b/pcsx2/DEV9/ATA/Commands/ATA_CmdExecuteDeviceDiag.cpp index 00c0a9441b..f21f0e648a 100644 --- a/pcsx2/DEV9/ATA/Commands/ATA_CmdExecuteDeviceDiag.cpp +++ b/pcsx2/DEV9/ATA/Commands/ATA_CmdExecuteDeviceDiag.cpp @@ -8,6 +8,7 @@ void ATA::PreCmdExecuteDeviceDiag() { regStatus |= ATA_STAT_BUSY; regStatus &= ~ATA_STAT_READY; + pendingInterrupt = false; dev9.irqcause &= ~ATA_INTR_INTRQ; //dev9.spd.regIntStat &= unchecked((UInt16)~DEV9Header.ATA_INTR_DMA_RDY); //Is this correct? } @@ -21,8 +22,12 @@ void ATA::PostCmdExecuteDeviceDiag(bool sendIRQ) // If Device Diagnostics is performed as part of a reset // then we don't raise an IRQ or set pending interrupt - if (regControlEnableIRQ && sendIRQ) - _DEV9irq(ATA_INTR_INTRQ, 1); + if (sendIRQ) + { + pendingInterrupt = true; + if (regControlEnableIRQ) + _DEV9irq(ATA_INTR_INTRQ, 1); + } } //GENRAL FEATURE SET diff --git a/pcsx2/DEV9/ATA/Commands/ATA_CmdNoData.cpp b/pcsx2/DEV9/ATA/Commands/ATA_CmdNoData.cpp index e92e19cb93..97d5aa0f69 100644 --- a/pcsx2/DEV9/ATA/Commands/ATA_CmdNoData.cpp +++ b/pcsx2/DEV9/ATA/Commands/ATA_CmdNoData.cpp @@ -8,6 +8,7 @@ void ATA::PostCmdNoData() { regStatus &= ~ATA_STAT_BUSY; + pendingInterrupt = true; if (regControlEnableIRQ) _DEV9irq(ATA_INTR_INTRQ, 1); } diff --git a/pcsx2/DEV9/ATA/Commands/ATA_CmdPIOData.cpp b/pcsx2/DEV9/ATA/Commands/ATA_CmdPIOData.cpp index d2db7052ad..36650c3d47 100644 --- a/pcsx2/DEV9/ATA/Commands/ATA_CmdPIOData.cpp +++ b/pcsx2/DEV9/ATA/Commands/ATA_CmdPIOData.cpp @@ -15,8 +15,12 @@ void ATA::DRQCmdPIODataToHost(u8* buff, int buffLen, int buffIndex, int size, bo regStatus &= ~ATA_STAT_BUSY; regStatus |= ATA_STAT_DRQ; + // Only set pendingInterrupt if nIEN is cleared if (regControlEnableIRQ && sendIRQ) - _DEV9irq(ATA_INTR_INTRQ, 1); //0x6c cycles before + { + pendingInterrupt = true; + _DEV9irq(ATA_INTR_INTRQ, 1); + } } void ATA::PostCmdPIODataToHost() {