diff --git a/pcsx2/DEV9/ATA/ATA.h b/pcsx2/DEV9/ATA/ATA.h index a18d64c670cdf..778f63cde4ff8 100644 --- a/pcsx2/DEV9/ATA/ATA.h +++ b/pcsx2/DEV9/ATA/ATA.h @@ -94,7 +94,11 @@ class ATA u8 regNsector; u8 regNsectorHOB; - u8 regStatus; //ReadOnly. When read via AlternateStatus pending interrupts are not cleared + u8 regStatus; // ReadOnly. When read via AlternateStatus, pending interrupts are not cleared. + // When an error occurs, the SEEK bit shall not be changed until the Status Register is read, + // after which this bit again indicates Seek completed. + // A value of -1 is locked clear, a value of 1 is locked set, 0 is unlocked. + s8 regStatusSeekLock; bool pendingInterrupt = false; diff --git a/pcsx2/DEV9/ATA/ATA_State.cpp b/pcsx2/DEV9/ATA/ATA_State.cpp index 59b400093a621..c53e4a506a1f8 100644 --- a/pcsx2/DEV9/ATA/ATA_State.cpp +++ b/pcsx2/DEV9/ATA/ATA_State.cpp @@ -317,6 +317,9 @@ void ATA::ResetEnd(bool hard) mdmaMode = 2; } + regStatus |= ATA_STAT_SEEK; + regStatusSeekLock = 0; + HDD_ExecuteDeviceDiag(false); regControlEnableIRQ = false; } @@ -391,6 +394,19 @@ u16 ATA::Read(u32 addr, int width) if (GetSelectedDevice() != 0) return 0; + + // When an error occurs, the seek bit shall not be changed until the Status Register is read, after which the bit then indicates the current Seek status. + // This handles reporting the locked value, and then unlocking if read form STATUS rather then ALT_STATUS. + // locking is performed where the errror occurs, by setting regStatusSeekLock to either 1 or -1 based on the locked SEEK value. + if (regStatusSeekLock != 0) + { + u8 hard = (regStatus & ~ATA_STAT_SEEK); + hard |= (regStatusSeekLock > 0) ? ATA_STAT_SEEK : static_cast(0); + if (addr == ATA_R_STATUS) + regStatusSeekLock = 0; + return hard; + } + return regStatus; default: Console.Error("DEV9: ATA: Unknown %dbit read at address %x", width, addr); diff --git a/pcsx2/DEV9/ATA/ATA_Transfer.cpp b/pcsx2/DEV9/ATA/ATA_Transfer.cpp index 7f8e85a92e7a6..cb4fc94d72722 100644 --- a/pcsx2/DEV9/ATA/ATA_Transfer.cpp +++ b/pcsx2/DEV9/ATA/ATA_Transfer.cpp @@ -482,9 +482,12 @@ bool ATA::HDD_CanAssessOrSetError() regError |= static_cast(ATA_ERR_ID); if (nsector == -1) { + regStatus &= ~ATA_STAT_SEEK; + regStatusSeekLock = -1; PostCmdNoData(); return false; } + regStatusSeekLock = 1; } return true; } diff --git a/pcsx2/DEV9/ATA/Commands/ATA_CmdDMA.cpp b/pcsx2/DEV9/ATA/Commands/ATA_CmdDMA.cpp index f3208a5905799..28dea8f7cc348 100644 --- a/pcsx2/DEV9/ATA/Commands/ATA_CmdDMA.cpp +++ b/pcsx2/DEV9/ATA/Commands/ATA_CmdDMA.cpp @@ -137,15 +137,19 @@ void ATA::HDD_ReadDMA(bool isLBA48) IDE_CmdLBA48Transform(isLBA48); + regStatus &= ~ATA_STAT_SEEK; if (!HDD_CanSeek()) { Console.Error("DEV9: ATA: Transfer from invalid LBA %lu", HDD_GetLBA()); nsector = -1; regStatus |= ATA_STAT_ERR; + regStatusSeekLock = -1; regError |= ATA_ERR_ID; PostCmdNoData(); return; } + else + regStatus |= ATA_STAT_SEEK; //Do Sync Read HDD_ReadSync(&ATA::DRQCmdDMADataToHost); @@ -159,15 +163,19 @@ void ATA::HDD_WriteDMA(bool isLBA48) IDE_CmdLBA48Transform(isLBA48); + regStatus &= ~ATA_STAT_SEEK; if (!HDD_CanSeek()) { Console.Error("DEV9: ATA: Transfer from invalid LBA %lu", HDD_GetLBA()); nsector = -1; regStatus |= ATA_STAT_ERR; + regStatusSeekLock = -1; regError |= ATA_ERR_ID; PostCmdNoData(); return; } + else + regStatus |= ATA_STAT_SEEK; //Do Async write DRQCmdDMADataFromHost(); diff --git a/pcsx2/DEV9/ATA/Commands/ATA_CmdNoData.cpp b/pcsx2/DEV9/ATA/Commands/ATA_CmdNoData.cpp index 218cbeaf82630..725e0b599522b 100644 --- a/pcsx2/DEV9/ATA/Commands/ATA_CmdNoData.cpp +++ b/pcsx2/DEV9/ATA/Commands/ATA_CmdNoData.cpp @@ -19,6 +19,7 @@ void ATA::CmdNoDataAbort() regError |= ATA_ERR_ABORT; regStatus |= ATA_STAT_ERR; + regStatusSeekLock = (regStatus & ATA_STAT_SEEK) ? 1 : -1; PostCmdNoData(); } @@ -30,8 +31,14 @@ void ATA::HDD_FlushCache() //Can't when DRQ set return; DevCon.WriteLn("DEV9: HDD_FlushCache"); - awaitFlush = true; - Async(-1); + if (!writeQueue.IsQueueEmpty()) + { + regStatus |= ATA_STAT_SEEK; + awaitFlush = true; + Async(-1); + } + else + PostCmdNoData(); } void ATA::HDD_InitDevParameters() @@ -52,6 +59,16 @@ void ATA::HDD_ReadVerifySectors(bool isLBA48) IDE_CmdLBA48Transform(isLBA48); + regStatus &= ~ATA_STAT_SEEK; + if (!HDD_CanSeek()) + { + regStatus |= ATA_STAT_ERR; + regStatusSeekLock = -1; + regError |= ATA_ERR_TRACK0; + } + else + regStatus |= ATA_STAT_SEEK; + HDD_CanAssessOrSetError(); PostCmdNoData(); @@ -84,12 +101,12 @@ void ATA::HDD_SeekCmd() return; DevCon.WriteLn("DEV9: HDD_SeekCmd"); - regStatus &= ~ATA_STAT_SEEK; - lba48 = false; + regStatus &= ~ATA_STAT_SEEK; if (HDD_CanSeek()) { regStatus |= ATA_STAT_ERR; + regStatusSeekLock = -1; regError |= ATA_ERR_ID; } else @@ -184,6 +201,7 @@ void ATA::HDD_Nop() //Always ends in error regError |= ATA_ERR_ABORT; regStatus |= ATA_STAT_ERR; + regStatusSeekLock = (regStatus & ATA_STAT_SEEK) ? 1 : -1; PostCmdNoData(); } diff --git a/pcsx2/DEV9/ATA/Commands/ATA_CmdPIOData.cpp b/pcsx2/DEV9/ATA/Commands/ATA_CmdPIOData.cpp index 36650c3d47ff5..a8ed39dfbb899 100644 --- a/pcsx2/DEV9/ATA/Commands/ATA_CmdPIOData.cpp +++ b/pcsx2/DEV9/ATA/Commands/ATA_CmdPIOData.cpp @@ -97,13 +97,17 @@ void ATA::HDD_ReadPIO(bool isLBA48) IDE_CmdLBA48Transform(isLBA48); + regStatus &= ~ATA_STAT_SEEK; if (!HDD_CanSeek()) { regStatus |= ATA_STAT_ERR; + regStatusSeekLock = -1; regError |= ATA_ERR_ID; PostCmdNoData(); return; } + else + regStatus |= ATA_STAT_SEEK; HDD_ReadSync(&ATA::HDD_ReadPIOS2); } diff --git a/pcsx2/DEV9/ATA/Commands/ATA_Command.cpp b/pcsx2/DEV9/ATA/Commands/ATA_Command.cpp index c3d44a8c31251..6fbd5152e00e6 100644 --- a/pcsx2/DEV9/ATA/Commands/ATA_Command.cpp +++ b/pcsx2/DEV9/ATA/Commands/ATA_Command.cpp @@ -142,8 +142,6 @@ bool ATA::PreCmd() regStatus &= ~ATA_STAT_DRQ; regStatus &= ~ATA_STAT_ERR; - regStatus &= ~ATA_STAT_SEEK; - regError = 0; return true;