Skip to content

Commit

Permalink
DEV9: Set/Clear SEEK bit in all relevent commands (#11931)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
TheLastRar authored Oct 23, 2024
1 parent 8afd29e commit a044b7c
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 7 deletions.
6 changes: 5 additions & 1 deletion pcsx2/DEV9/ATA/ATA.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
16 changes: 16 additions & 0 deletions pcsx2/DEV9/ATA/ATA_State.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,9 @@ void ATA::ResetEnd(bool hard)
mdmaMode = 2;
}

regStatus |= ATA_STAT_SEEK;
regStatusSeekLock = 0;

HDD_ExecuteDeviceDiag(false);
regControlEnableIRQ = false;
}
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions pcsx2/DEV9/ATA/ATA_Transfer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
8 changes: 8 additions & 0 deletions pcsx2/DEV9/ATA/Commands/ATA_CmdDMA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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();
Expand Down
26 changes: 22 additions & 4 deletions pcsx2/DEV9/ATA/Commands/ATA_CmdNoData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ void ATA::CmdNoDataAbort()

regError |= ATA_ERR_ABORT;
regStatus |= ATA_STAT_ERR;
regStatusSeekLock = (regStatus & ATA_STAT_SEEK) ? 1 : -1;
PostCmdNoData();
}

Expand All @@ -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()
Expand All @@ -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();
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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();
}

Expand Down
4 changes: 4 additions & 0 deletions pcsx2/DEV9/ATA/Commands/ATA_CmdPIOData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
2 changes: 0 additions & 2 deletions pcsx2/DEV9/ATA/Commands/ATA_Command.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,6 @@ bool ATA::PreCmd()
regStatus &= ~ATA_STAT_DRQ;
regStatus &= ~ATA_STAT_ERR;

regStatus &= ~ATA_STAT_SEEK;

regError = 0;

return true;
Expand Down

0 comments on commit a044b7c

Please sign in to comment.