CDVD: Add some error handling, fix up some IRQ stuff

This commit is contained in:
refractionpcsx2 2021-12-26 08:12:29 +00:00
parent 8dd51b7207
commit 7d9c8c9172
4 changed files with 53 additions and 53 deletions

View File

@ -610,6 +610,13 @@ s32 cdvdReadSubQ(s32 lsn, cdvdSubQ* subq)
static void cdvdDetectDisk()
{
cdvd.Type = DoCDVDdetectDiskType();
if (cdvd.Type != 0)
{
cdvdTD td;
CDVD->getTD(0, &td);
cdvd.MaxSector = td.lsn;
}
}
s32 cdvdCtrlTrayOpen()
@ -1056,7 +1063,6 @@ __fi void cdvdActionInterrupt()
cdvd.Sector = cdvd.SeekToSector;
cdvd.Status = CDVD_STATUS_PAUSE;
cdvd.nextSectorsBuffered = 0;
cdvd.triggerDataReady = true;
CDVDSECTORREADY_INT(cdvd.ReadTime);
break;
@ -1067,7 +1073,6 @@ __fi void cdvdActionInterrupt()
cdvd.Sector = cdvd.SeekToSector;
cdvd.Status = CDVD_STATUS_PAUSE;
cdvd.nextSectorsBuffered = 0;
cdvd.triggerDataReady = true;
CDVDSECTORREADY_INT(cdvd.ReadTime);
break;
@ -1092,10 +1097,8 @@ __fi void cdvdActionInterrupt()
break;
}
cdvd.Action = cdvdAction_None;
cdvd.nCommand = 0;
cdvd.PwOff |= 1 << Irq_CommandComplete;
psxHu32(0x1070) |= 0x4;
cdvdSetIrq();
}
__fi void cdvdSectorReady()
@ -1104,19 +1107,6 @@ __fi void cdvdSectorReady()
{
cdvd.nextSectorsBuffered++;
CDVD_LOG("Buffering sector");
//DevCon.Warning("Bufferred Sector %d cur seek %d ready %x", cdvd.Sector, cdvd.SeekToSector, cdvd.Ready);
if (cdvd.nextSectorsBuffered == 16 && cdvd.triggerDataReady)
{
CDVD_LOG("Interrupting to say data ready");
if (!(cdvd.PwOff & (1 << Irq_DataReady)))
{
cdvd.PwOff |= (1 << Irq_DataReady);
iopIntcIrq(2);
}
cdvd.Ready |= CDVD_DRIVE_DATARDY;
cdvd.triggerDataReady = false;
}
}
if (cdvd.nextSectorsBuffered < 16)
@ -1214,14 +1204,10 @@ __fi void cdvdReadInterrupt()
{
// Setting the data ready flag fixes a black screen loading issue in
// Street Fighter Ex3 (NTSC-J version).
cdvd.PwOff |= (1 << Irq_CommandComplete) | (1 << Irq_DataReady);
//psxHu32(0x1070) |= 0x4;
iopIntcIrq(2);
cdvdSetIrq();
cdvd.Ready |= CDVD_DRIVE_READY;
cdvd.Status = CDVD_STATUS_PAUSE;
cdvd.nCommand = 0;
//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.
@ -1235,24 +1221,12 @@ __fi void cdvdReadInterrupt()
{
if (cdvd.nSectors <= 0)
{
cdvd.PwOff |= (1 << Irq_CommandComplete) | (1 << Irq_DataReady);
cdvdSetIrq();
//psxHu32(0x1070) |= 0x4;
iopIntcIrq(2);
cdvd.Ready |= CDVD_DRIVE_READY;
cdvd.Status = CDVD_STATUS_PAUSE;
cdvd.nCommand = 0;
if (!HW_DMA3_BCR_H16)
{
if (HW_DMA3_CHCR & 0x01000000)
{
HW_DMA3_CHCR &= ~0x01000000;
psxDmaInterrupt(3);
}
}
return;
}
CDVDREAD_INT((cdvd.BlockSize / 4) * 12);
@ -1280,7 +1254,6 @@ static uint cdvdStartSeek(uint newsector, CDVD_MODE_TYPE mode)
cdvd.Ready &= ~(CDVD_DRIVE_READY | CDVD_DRIVE_DATARDY);
cdvd.Reading = 1;
cdvd.Readed = 0;
cdvd.triggerDataReady = false;
// Okay so let's explain this, since people keep messing with it in the past and just poking it.
// So when the drive is spinning, bit 0x2 is set on the Status, and bit 0x8 is set when the drive is not reading.
// So In the case where it's seeking to data it will be Spinning (0x2) not reading (0x8) and Seeking (0x10, but because seeking is also spinning 0x2 is also set))
@ -1607,6 +1580,27 @@ u8 cdvdRead(u8 key)
}
}
static bool cdvdReadErrorHandler()
{
if (cdvd.nSectors <= 0)
{
DevCon.Warning("Bad Sector Count Error");
cdvd.Error = 0x21; // Number of read sectors abnormal
cdvdSetIrq();
return false;
}
if (cdvd.SeekToSector > cdvd.MaxSector)
{
DevCon.Warning("Invalid Sector Error");
cdvd.Error = 0x20; // Sector position is abnormal
cdvdSetIrq();
return false;
}
return true;
}
static void cdvdWrite04(u8 rt)
{ // NCOMMAND
CDVD_LOG("cdvdWrite04: NCMD %s (%x) (ParamP = %x)", nCmdName[rt], rt, cdvd.ParamP);
@ -1638,7 +1632,6 @@ static void cdvdWrite04(u8 rt)
DevCon.Warning("CdStop : %d", rt);
cdvd.Action = cdvdAction_Stop;
cdvd.nextSectorsBuffered = 0;
cdvd.triggerDataReady = true;
psxRegs.interrupt &= ~(1 << IopEvt_CdvdSectorReady);
cdvd.Status = CDVD_STATUS_SPIN;
CDVD_INT(PSXCLK / 6); // 166ms delay?
@ -1650,11 +1643,9 @@ static void cdvdWrite04(u8 rt)
psxRegs.interrupt &= ~(1 << IopEvt_Cdvd);
cdvd.Ready |= CDVD_DRIVE_READY;
cdvdSetIrq();
cdvd.nCommand = 0;
//After Pausing needs to buffer the next sector
cdvd.Status = CDVD_STATUS_PAUSE;
cdvd.nextSectorsBuffered = 0;
cdvd.triggerDataReady = true;
CDVDSECTORREADY_INT(cdvd.ReadTime);
break;
@ -1729,6 +1720,9 @@ static void cdvdWrite04(u8 rt)
break;
}
if (!cdvdReadErrorHandler())
break;
CDVD_LOG("CDRead > startSector=%d, seekTo=%d nSectors=%d, RetryCnt=%x, Speed=%dx(%s), ReadMode=%x(%x) SpindleCtrl=%x",
cdvd.Sector, cdvd.SeekToSector, cdvd.nSectors, cdvd.RetryCnt, cdvd.Speed, (cdvd.SpindlCtrl & CDVD_SPINDLE_CAV) ? L"CAV" : L"CLV", cdvd.ReadMode, cdvd.Param[10], cdvd.SpindlCtrl);
@ -1850,6 +1844,9 @@ static void cdvdWrite04(u8 rt)
cdvd.ReadMode = CDVD_MODE_2048;
cdvd.BlockSize = 2064;
if (!cdvdReadErrorHandler())
break;
CDVD_LOG("DvdRead > startSector=%d, seekTo=%d nSectors=%d, RetryCnt=%x, Speed=%dx(%s), ReadMode=%x(%x) SpindleCtrl=%x",
cdvd.Sector, cdvd.SeekToSector, cdvd.nSectors, cdvd.RetryCnt, cdvd.Speed, (cdvd.SpindlCtrl & CDVD_SPINDLE_CAV) ? L"CAV" : L"CLV", cdvd.ReadMode, cdvd.Param[10], cdvd.SpindlCtrl);
@ -1880,13 +1877,11 @@ static void cdvdWrite04(u8 rt)
//}
cdvdGetToc(iopPhysMem(HW_DMA3_MADR));
cdvdSetIrq();
cdvd.nCommand = 0;
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;
cdvd.nextSectorsBuffered = 0;
cdvd.triggerDataReady = true;
CDVDSECTORREADY_INT(cdvd.ReadTime);
break;
@ -1899,11 +1894,9 @@ static void cdvdWrite04(u8 rt)
cdvdReadKey(arg0, arg1, arg2, cdvd.Key);
cdvd.KeyXor = 0x00;
cdvdSetIrq();
cdvd.nCommand = 0;
//After reading the key it needs to go back to buffer the next sector
cdvd.Status = CDVD_STATUS_PAUSE;
cdvd.nextSectorsBuffered = 0;
cdvd.triggerDataReady = true;
CDVDSECTORREADY_INT(cdvd.ReadTime);
}
break;
@ -1911,13 +1904,11 @@ static void cdvdWrite04(u8 rt)
case N_CD_CHG_SPDL_CTRL: // CdChgSpdlCtrl
Console.WriteLn("sceCdChgSpdlCtrl(%d)", cdvd.Param[0]);
cdvdSetIrq();
cdvd.nCommand = 0;
break;
default:
Console.Warning("NCMD Unknown %x", rt);
cdvdSetIrq();
cdvd.nCommand = 0;
break;
}
cdvd.ParamP = 0;
@ -1963,18 +1954,12 @@ static __fi void cdvdWrite07(u8 rt) // BREAK
cdvd.Readed = 0;
cdvd.Reading = 0;
cdvd.Status = CDVD_STATUS_STOP;
//cdvd.nCommand = 0;
}
static __fi void cdvdWrite08(u8 rt)
{ // INTR_STAT
CDVD_LOG("cdvdWrite08(IntrReason) = ACK(%x)", rt);
cdvd.PwOff &= ~rt;
if (rt & (1 << Irq_DataReady))
{
CDVD_LOG("Data ready acknowledged");
cdvd.Ready &= ~CDVD_DRIVE_DATARDY;
}
}
static __fi void cdvdWrite0A(u8 rt)

View File

@ -148,12 +148,12 @@ struct cdvdStruct
u8 TrayTimeout;
u8 Action; // the currently scheduled emulated action
u32 SeekToSector; // Holds the destination sector during seek operations.
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;
bool triggerDataReady;
};
extern cdvdStruct cdvd;

View File

@ -38,6 +38,8 @@ without proper emulation of the cdvd status flag it also tends to break things.
*/
/* Old IRQ structure
enum CdvdIrqId
{
Irq_None = 0,
@ -49,6 +51,16 @@ enum CdvdIrqId
Irq_NotReady
};
*/
enum CdvdIrqId
{
Irq_None = 0,
Irq_CommandComplete = 0,
Irq_POffReady = 2,
Irq_Eject,
Irq_BSPower, //PS1 IRQ not used
};
/* Cdvd.Status bits and their meaning
0x0 = Stop

View File

@ -1074,6 +1074,9 @@ void psxDma3(u32 madr, u32 bcr, u32 chcr)
break;
case 0x41000200:
if (HW_DMA3_BCR_H16 == 0)
break;
if (cdvd.WaitingDMA)
{
PSX_INT(IopEvt_CdvdRead, (cdvd.BlockSize / 4) * 12); //Data should be already buffered so simulate DMA time