CDVD: Improve status handling/implement sticky status

This commit is contained in:
refractionpcsx2 2021-12-26 11:41:20 +00:00
parent 5546b102eb
commit 1e11d40828
2 changed files with 42 additions and 55 deletions

View File

@ -619,6 +619,12 @@ static void cdvdDetectDisk()
}
}
static void cdvdUpdateStatus(cdvdStatus NewStatus)
{
cdvd.Status = NewStatus;
cdvd.StatusSticky |= NewStatus;
}
s32 cdvdCtrlTrayOpen()
{
DevCon.WriteLn(Color_Green, L"Open virtual disk tray");
@ -633,11 +639,9 @@ s32 cdvdCtrlTrayOpen()
cdvdDetectDisk();
DiscSwapTimerSeconds = cdvd.RTC.second; // remember the PS2 time when this happened
cdvd.Status = CDVD_STATUS_TRAY_OPEN;
cdvdUpdateStatus(CDVD_STATUS_TRAY_OPEN);
cdvd.Ready = CDVD_DRIVE_BUSY | CDVD_DRIVE_DEV9CON;
cdvd.mediaChanged = true;
if (cdvd.Type > 0 || CDVDsys_GetSourceType() == CDVD_SourceType::NoDisc)
{
cdvd.Tray.cdvdActionSeconds = 3;
@ -656,7 +660,7 @@ s32 cdvdCtrlTrayClose()
{
DevCon.WriteLn(Color_Green, L"Media already loaded (fast boot)");
cdvd.Ready = CDVD_DRIVE_READY | CDVD_DRIVE_DEV9CON;
cdvd.Status = CDVD_STATUS_PAUSE;
cdvdUpdateStatus(CDVD_STATUS_PAUSE);
cdvd.Tray.trayState = CDVD_DISC_ENGAGED;
cdvd.Tray.cdvdActionSeconds = 0;
}
@ -664,7 +668,7 @@ s32 cdvdCtrlTrayClose()
{
DevCon.WriteLn(Color_Green, L"Detecting media");
cdvd.Ready = CDVD_DRIVE_BUSY | CDVD_DRIVE_DEV9CON;
cdvd.Status = CDVD_STATUS_SEEK;
cdvdUpdateStatus(CDVD_STATUS_SEEK);
cdvd.Tray.trayState = CDVD_DISC_DETECTING;
cdvd.Tray.cdvdActionSeconds = 3;
}
@ -812,7 +816,7 @@ void cdvdReset()
cdvd.sDataIn = 0x40;
cdvd.Ready = CDVD_DRIVE_READY | CDVD_DRIVE_DEV9CON;
cdvd.Status = CDVD_STATUS_PAUSE;
cdvdUpdateStatus(CDVD_STATUS_PAUSE);
cdvd.Speed = 4;
cdvd.BlockSize = 2064;
cdvd.Action = cdvdAction_None;
@ -904,10 +908,9 @@ void cdvdNewDiskCB()
if ((g_GameStarted || !g_SkipBiosHack) && cdvd.Tray.trayState != CDVD_DISC_EJECT)
{
DevCon.WriteLn(Color_Green, L"Ejecting media");
cdvd.Status = CDVD_STATUS_TRAY_OPEN;
cdvdUpdateStatus(CDVD_STATUS_TRAY_OPEN);
cdvd.Ready = CDVD_DRIVE_BUSY | CDVD_DRIVE_DEV9CON;
cdvd.Tray.trayState = CDVD_DISC_EJECT;
cdvd.mediaChanged = true;
// If it really got ejected, the DVD Reader will report Type 0, so no need to simulate ejection
if (cdvd.Type > 0)
@ -917,7 +920,7 @@ void cdvdNewDiskCB()
{
DevCon.WriteLn(Color_Green, L"Seeking new media");
cdvd.Ready = CDVD_DRIVE_BUSY | CDVD_DRIVE_DEV9CON;
cdvd.Status = CDVD_STATUS_SEEK;
cdvdUpdateStatus(CDVD_STATUS_SEEK);
cdvd.Tray.trayState = CDVD_DISC_DETECTING;
cdvd.Tray.cdvdActionSeconds = 3;
}
@ -1061,7 +1064,7 @@ __fi void cdvdActionInterrupt()
cdvd.Spinning = true;
cdvd.Ready = CDVD_DRIVE_READY | CDVD_DRIVE_DEV9CON;
cdvd.Sector = cdvd.SeekToSector;
cdvd.Status = CDVD_STATUS_PAUSE;
cdvdUpdateStatus(CDVD_STATUS_PAUSE);
cdvd.nextSectorsBuffered = 0;
CDVDSECTORREADY_INT(cdvd.ReadTime);
break;
@ -1071,7 +1074,7 @@ __fi void cdvdActionInterrupt()
cdvd.Spinning = true; //check (rama)
cdvd.Ready = CDVD_DRIVE_READY | CDVD_DRIVE_DEV9CON;
cdvd.Sector = cdvd.SeekToSector;
cdvd.Status = CDVD_STATUS_PAUSE;
cdvdUpdateStatus(CDVD_STATUS_PAUSE);
cdvd.nextSectorsBuffered = 0;
CDVDSECTORREADY_INT(cdvd.ReadTime);
break;
@ -1080,7 +1083,7 @@ __fi void cdvdActionInterrupt()
cdvd.Spinning = false;
cdvd.Ready = CDVD_DRIVE_READY | CDVD_DRIVE_DEV9CON;
cdvd.Sector = 0;
cdvd.Status = CDVD_STATUS_STOP;
cdvdUpdateStatus(CDVD_STATUS_STOP);
break;
case cdvdAction_Break:
@ -1092,7 +1095,7 @@ __fi void cdvdActionInterrupt()
cdvd.Reading = 0;
cdvd.Readed = 0;
cdvd.Ready = CDVD_DRIVE_READY | CDVD_DRIVE_DEV9CON | CDVD_DRIVE_ERROR; // should be CDVD_READY1 or something else?
cdvd.Status = CDVD_STATUS_PAUSE; //Break stops the command in progress it doesn't stop the drive. Formula 2001
cdvdUpdateStatus(CDVD_STATUS_PAUSE);
cdvd.RErr = 0;
break;
}
@ -1119,7 +1122,7 @@ __fi void cdvdReadInterrupt()
//Console.WriteLn("cdvdReadInterrupt %x %x %x %x %x", cpuRegs.interrupt, cdvd.Readed, cdvd.Reading, cdvd.nSectors, (HW_DMA3_BCR_H16 * HW_DMA3_BCR_L16) *4);
cdvd.Ready = CDVD_DRIVE_BUSY | CDVD_DRIVE_DEV9CON;
cdvd.Status = CDVD_STATUS_READ;
cdvdUpdateStatus(CDVD_STATUS_READ);
cdvd.WaitingDMA = false;
if (!cdvd.Readed)
@ -1189,7 +1192,7 @@ __fi void cdvdReadInterrupt()
psxHu32(0x1070) |= 0x4;
cdvd.Ready |= CDVD_DRIVE_DATARDY;
}*/
cdvd.Status = CDVD_STATUS_PAUSE;
cdvdUpdateStatus(CDVD_STATUS_PAUSE);
cdvd.WaitingDMA = true;
return;
}
@ -1207,7 +1210,7 @@ __fi void cdvdReadInterrupt()
cdvdSetIrq();
cdvd.Ready = CDVD_DRIVE_READY | CDVD_DRIVE_DEV9CON;
cdvd.Status = CDVD_STATUS_PAUSE;
cdvdUpdateStatus(CDVD_STATUS_PAUSE);
//DevCon.Warning("Scheduling interrupt in %d cycles", cdvd.ReadTime - ((cdvd.BlockSize / 4) * 12));
// Timing issues on command end
// Star Ocean (1.1 Japan) expects the DMA to end and interrupt at least 128 or more cycles before the CDVD command ends.
@ -1226,7 +1229,7 @@ __fi void cdvdReadInterrupt()
iopIntcIrq(2);
cdvd.Ready = CDVD_DRIVE_READY | CDVD_DRIVE_DEV9CON;
cdvd.Status = CDVD_STATUS_PAUSE;
cdvdUpdateStatus(CDVD_STATUS_PAUSE);
return;
}
CDVDREAD_INT((cdvd.BlockSize / 4) * 12);
@ -1260,7 +1263,7 @@ static uint cdvdStartSeek(uint newsector, CDVD_MODE_TYPE mode)
// Update - Apparently all that was rubbish and some games don't like it. WRC was the one in this scenario which hated SEEK |ZPAUSE, so just putting it back to pause for now.
// We should really run some tests for this behaviour.
cdvd.Status = CDVD_STATUS_PAUSE;
cdvdUpdateStatus(CDVD_STATUS_PAUSE);
if (!cdvd.Spinning)
{
@ -1299,7 +1302,7 @@ static uint cdvdStartSeek(uint newsector, CDVD_MODE_TYPE mode)
if (delta == 0)
{
//cdvd.Status = CDVD_STATUS_PAUSE;
cdvd.Status = CDVD_STATUS_READ; // Time Crisis 2
cdvdUpdateStatus(CDVD_STATUS_READ);
cdvd.Readed = 1; // Note: 1, not 0, as implied by the next comment. Need to look into this. --arcum42
cdvd.Reading = 1; // We don't need to wait for it to read a sector as it's already queued up, or we adjust for it here.
cdvd.RetryCntP = 0;
@ -1372,11 +1375,12 @@ void cdvdUpdateTrayState()
if (CDVDsys_GetSourceType() != CDVD_SourceType::NoDisc)
{
DevCon.WriteLn(Color_Green, L"Media ready to read");
cdvd.mediaChanged = true;
cdvd.Status = CDVD_STATUS_PAUSE;
cdvdUpdateStatus(CDVD_STATUS_PAUSE);
}
else
cdvd.Status = CDVD_STATUS_STOP;
{
cdvdUpdateStatus(CDVD_STATUS_STOP);
}
break;
}
}
@ -1470,13 +1474,10 @@ u8 cdvdRead(u8 key)
CDVD_LOG("cdvdRead0A(Status) %x", cdvd.Status);
return cdvd.Status;
case 0x0B: // MEDIA CHANGED (Set when disc is ejected or detected, aka cdvd.type changes)
case 0x0B: // STATUS STICKY
{
CDVD_LOG("cdvdRead0B(Media Change) (1 Changed, 0 Not Changed): %x", cdvd.mediaChanged);
bool ret = cdvd.mediaChanged;
cdvd.mediaChanged = false;
return ret;
CDVD_LOG("cdvdRead0B(Status Sticky): %x", cdvd.StatusSticky);
return cdvd.StatusSticky;
}
case 0x0C: // CRT MINUTE
CDVD_LOG("cdvdRead0C(Min) %x", itob((u8)(cdvd.Sector / (60 * 75))));
@ -1627,7 +1628,7 @@ static void cdvdWrite04(u8 rt)
CDVD_INT(cdvdStartSeek(0, MODE_DVDROM));
// Might not seek, but makes sense since it does move to the inner most track
// It's only temporary until the interrupt anyway when it sets itself ready
cdvd.Status = CDVD_STATUS_SEEK;
cdvdUpdateStatus(CDVD_STATUS_SEEK);
break;
case N_CD_STOP: // CdStop
@ -1635,7 +1636,7 @@ static void cdvdWrite04(u8 rt)
cdvd.Action = cdvdAction_Stop;
cdvd.nextSectorsBuffered = 0;
psxRegs.interrupt &= ~(1 << IopEvt_CdvdSectorReady);
cdvd.Status = CDVD_STATUS_SPIN;
cdvdUpdateStatus(CDVD_STATUS_SPIN);
CDVD_INT(PSXCLK / 6); // 166ms delay?
break;
@ -1646,7 +1647,7 @@ static void cdvdWrite04(u8 rt)
cdvd.Ready = CDVD_DRIVE_READY | CDVD_DRIVE_DEV9CON;
cdvdSetIrq();
//After Pausing needs to buffer the next sector
cdvd.Status = CDVD_STATUS_PAUSE;
cdvdUpdateStatus(CDVD_STATUS_PAUSE);
cdvd.nextSectorsBuffered = 0;
CDVDSECTORREADY_INT(cdvd.ReadTime);
break;
@ -1655,7 +1656,7 @@ static void cdvdWrite04(u8 rt)
cdvd.Action = cdvdAction_Seek;
cdvd.ReadTime = cdvdBlockReadTime((CDVD_MODE_TYPE)cdvdIsDVD());
CDVD_INT(cdvdStartSeek(*(uint*)(cdvd.Param + 0), (CDVD_MODE_TYPE)cdvdIsDVD()));
cdvd.Status = CDVD_STATUS_SEEK;
cdvdUpdateStatus(CDVD_STATUS_SEEK);
break;
case N_CD_READ: // CdRead
@ -1882,7 +1883,7 @@ static void cdvdWrite04(u8 rt)
HW_DMA3_CHCR &= ~0x01000000;
psxDmaInterrupt(3);
//After reading the TOC it needs to go back to buffer the next sector
cdvd.Status = CDVD_STATUS_PAUSE;
cdvdUpdateStatus(CDVD_STATUS_PAUSE);
cdvd.nextSectorsBuffered = 0;
CDVDSECTORREADY_INT(cdvd.ReadTime);
break;
@ -1897,7 +1898,7 @@ static void cdvdWrite04(u8 rt)
cdvd.KeyXor = 0x00;
cdvdSetIrq();
//After reading the key it needs to go back to buffer the next sector
cdvd.Status = CDVD_STATUS_PAUSE;
cdvdUpdateStatus(CDVD_STATUS_PAUSE);
cdvd.nextSectorsBuffered = 0;
CDVDSECTORREADY_INT(cdvd.ReadTime);
}
@ -1955,7 +1956,7 @@ static __fi void cdvdWrite07(u8 rt) // BREAK
// Clear the cdvd status:
cdvd.Readed = 0;
cdvd.Reading = 0;
cdvd.Status = CDVD_STATUS_STOP;
cdvdUpdateStatus(CDVD_STATUS_STOP);
}
static __fi void cdvdWrite08(u8 rt)
@ -2066,27 +2067,13 @@ static void cdvdWrite16(u8 rt) // SCOMMAND
}
break;
case 0x05: // CdTrayReqState (0:1) - resets the tray open detection
// Fixme: This function is believed to change some status flag
// when the Tray state (stored as "1" in cdvd.Status) is different between 2 successive calls.
// Cdvd.Status can be different than 1 here, yet we may still have to report an open status.
// Gonna have to investigate further. (rama)
case 0x05: // CdTrayReqState (0:1) - resets the tray open detection
//Console.Warning("CdTrayReqState. cdvd.Status = %d", cdvd.Status);
// This function sets the Sticky tray flag to the same value as Status for detecting change
cdvd.StatusSticky = cdvd.Status & CDVD_STATUS_TRAY_OPEN;
SetResultSize(1);
if (cdvd.Status == CDVD_STATUS_TRAY_OPEN)
{
//Console.Warning( "reporting Open status" );
cdvd.Result[0] = 1;
}
else
{
//Console.Warning( "reporting Close status" );
cdvd.Result[0] = 0; // old behaviour was always this
}
cdvd.Result[0] = 0; // Could be a bit to say it's busy, but actual function is unknown, it expects 0 to continue.
break;
case 0x06: // CdTrayCtrl (1:1)

View File

@ -97,6 +97,7 @@ struct cdvdStruct
u8 Error;
u8 PwOff;
u8 Status;
u8 StatusSticky;
u8 Type;
u8 sCommand;
u8 sDataIn;
@ -151,7 +152,6 @@ struct cdvdStruct
u32 MaxSector; // Current disc max sector.
u32 ReadTime; // Avg. time to read one block of data (in Iop cycles)
bool Spinning; // indicates if the Cdvd is spinning or needs a spinup delay
bool mediaChanged;
cdvdTrayTimer Tray;
u8 nextSectorsBuffered;
};