DEV9: Set/Clear SEEK bit in all relevent commands (#11931)

* DEV9: Set SEEK on all successful seeks

* DEV9: Complete HDD_Flush immediately when write queue is empty

Also set SEEK when write queue isn't empty

* DEV9: Lock reported value of SEEK when errored
This commit is contained in:
TheLastRar 2024-10-23 13:36:16 +01:00 committed by GitHub
parent 8afd29e1a2
commit a044b7cf6e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 58 additions and 7 deletions

View File

@ -94,7 +94,11 @@ private:
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;

View File

@ -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<u8>(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);

View File

@ -482,9 +482,12 @@ bool ATA::HDD_CanAssessOrSetError()
regError |= static_cast<u8>(ATA_ERR_ID);
if (nsector == -1)
{
regStatus &= ~ATA_STAT_SEEK;
regStatusSeekLock = -1;
PostCmdNoData();
return false;
}
regStatusSeekLock = 1;
}
return true;
}

View File

@ -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();

View File

@ -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();
}

View File

@ -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);
}

View File

@ -142,8 +142,6 @@ bool ATA::PreCmd()
regStatus &= ~ATA_STAT_DRQ;
regStatus &= ~ATA_STAT_ERR;
regStatus &= ~ATA_STAT_SEEK;
regError = 0;
return true;