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() static void cdvdDetectDisk()
{ {
cdvd.Type = DoCDVDdetectDiskType(); cdvd.Type = DoCDVDdetectDiskType();
if (cdvd.Type != 0)
{
cdvdTD td;
CDVD->getTD(0, &td);
cdvd.MaxSector = td.lsn;
}
} }
s32 cdvdCtrlTrayOpen() s32 cdvdCtrlTrayOpen()
@ -1056,7 +1063,6 @@ __fi void cdvdActionInterrupt()
cdvd.Sector = cdvd.SeekToSector; cdvd.Sector = cdvd.SeekToSector;
cdvd.Status = CDVD_STATUS_PAUSE; cdvd.Status = CDVD_STATUS_PAUSE;
cdvd.nextSectorsBuffered = 0; cdvd.nextSectorsBuffered = 0;
cdvd.triggerDataReady = true;
CDVDSECTORREADY_INT(cdvd.ReadTime); CDVDSECTORREADY_INT(cdvd.ReadTime);
break; break;
@ -1067,7 +1073,6 @@ __fi void cdvdActionInterrupt()
cdvd.Sector = cdvd.SeekToSector; cdvd.Sector = cdvd.SeekToSector;
cdvd.Status = CDVD_STATUS_PAUSE; cdvd.Status = CDVD_STATUS_PAUSE;
cdvd.nextSectorsBuffered = 0; cdvd.nextSectorsBuffered = 0;
cdvd.triggerDataReady = true;
CDVDSECTORREADY_INT(cdvd.ReadTime); CDVDSECTORREADY_INT(cdvd.ReadTime);
break; break;
@ -1092,10 +1097,8 @@ __fi void cdvdActionInterrupt()
break; break;
} }
cdvd.Action = cdvdAction_None; cdvd.Action = cdvdAction_None;
cdvd.nCommand = 0;
cdvd.PwOff |= 1 << Irq_CommandComplete; cdvdSetIrq();
psxHu32(0x1070) |= 0x4;
} }
__fi void cdvdSectorReady() __fi void cdvdSectorReady()
@ -1104,19 +1107,6 @@ __fi void cdvdSectorReady()
{ {
cdvd.nextSectorsBuffered++; cdvd.nextSectorsBuffered++;
CDVD_LOG("Buffering sector"); 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) if (cdvd.nextSectorsBuffered < 16)
@ -1214,14 +1204,10 @@ __fi void cdvdReadInterrupt()
{ {
// Setting the data ready flag fixes a black screen loading issue in // Setting the data ready flag fixes a black screen loading issue in
// Street Fighter Ex3 (NTSC-J version). // Street Fighter Ex3 (NTSC-J version).
cdvd.PwOff |= (1 << Irq_CommandComplete) | (1 << Irq_DataReady); cdvdSetIrq();
//psxHu32(0x1070) |= 0x4;
iopIntcIrq(2);
cdvd.Ready |= CDVD_DRIVE_READY; cdvd.Ready |= CDVD_DRIVE_READY;
cdvd.Status = CDVD_STATUS_PAUSE; cdvd.Status = CDVD_STATUS_PAUSE;
cdvd.nCommand = 0;
//DevCon.Warning("Scheduling interrupt in %d cycles", cdvd.ReadTime - ((cdvd.BlockSize / 4) * 12)); //DevCon.Warning("Scheduling interrupt in %d cycles", cdvd.ReadTime - ((cdvd.BlockSize / 4) * 12));
// Timing issues on command end // 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. // 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) if (cdvd.nSectors <= 0)
{ {
cdvd.PwOff |= (1 << Irq_CommandComplete) | (1 << Irq_DataReady); cdvdSetIrq();
//psxHu32(0x1070) |= 0x4; //psxHu32(0x1070) |= 0x4;
iopIntcIrq(2); iopIntcIrq(2);
cdvd.Ready |= CDVD_DRIVE_READY; cdvd.Ready |= CDVD_DRIVE_READY;
cdvd.Status = CDVD_STATUS_PAUSE; 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; return;
} }
CDVDREAD_INT((cdvd.BlockSize / 4) * 12); 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.Ready &= ~(CDVD_DRIVE_READY | CDVD_DRIVE_DATARDY);
cdvd.Reading = 1; cdvd.Reading = 1;
cdvd.Readed = 0; 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. // 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 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)) // 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) static void cdvdWrite04(u8 rt)
{ // NCOMMAND { // NCOMMAND
CDVD_LOG("cdvdWrite04: NCMD %s (%x) (ParamP = %x)", nCmdName[rt], rt, cdvd.ParamP); 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); DevCon.Warning("CdStop : %d", rt);
cdvd.Action = cdvdAction_Stop; cdvd.Action = cdvdAction_Stop;
cdvd.nextSectorsBuffered = 0; cdvd.nextSectorsBuffered = 0;
cdvd.triggerDataReady = true;
psxRegs.interrupt &= ~(1 << IopEvt_CdvdSectorReady); psxRegs.interrupt &= ~(1 << IopEvt_CdvdSectorReady);
cdvd.Status = CDVD_STATUS_SPIN; cdvd.Status = CDVD_STATUS_SPIN;
CDVD_INT(PSXCLK / 6); // 166ms delay? CDVD_INT(PSXCLK / 6); // 166ms delay?
@ -1650,11 +1643,9 @@ static void cdvdWrite04(u8 rt)
psxRegs.interrupt &= ~(1 << IopEvt_Cdvd); psxRegs.interrupt &= ~(1 << IopEvt_Cdvd);
cdvd.Ready |= CDVD_DRIVE_READY; cdvd.Ready |= CDVD_DRIVE_READY;
cdvdSetIrq(); cdvdSetIrq();
cdvd.nCommand = 0;
//After Pausing needs to buffer the next sector //After Pausing needs to buffer the next sector
cdvd.Status = CDVD_STATUS_PAUSE; cdvd.Status = CDVD_STATUS_PAUSE;
cdvd.nextSectorsBuffered = 0; cdvd.nextSectorsBuffered = 0;
cdvd.triggerDataReady = true;
CDVDSECTORREADY_INT(cdvd.ReadTime); CDVDSECTORREADY_INT(cdvd.ReadTime);
break; break;
@ -1729,6 +1720,9 @@ static void cdvdWrite04(u8 rt)
break; break;
} }
if (!cdvdReadErrorHandler())
break;
CDVD_LOG("CDRead > startSector=%d, seekTo=%d nSectors=%d, RetryCnt=%x, Speed=%dx(%s), ReadMode=%x(%x) SpindleCtrl=%x", 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); 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.ReadMode = CDVD_MODE_2048;
cdvd.BlockSize = 2064; 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_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); 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)); cdvdGetToc(iopPhysMem(HW_DMA3_MADR));
cdvdSetIrq(); cdvdSetIrq();
cdvd.nCommand = 0;
HW_DMA3_CHCR &= ~0x01000000; HW_DMA3_CHCR &= ~0x01000000;
psxDmaInterrupt(3); psxDmaInterrupt(3);
//After reading the TOC it needs to go back to buffer the next sector //After reading the TOC it needs to go back to buffer the next sector
cdvd.Status = CDVD_STATUS_PAUSE; cdvd.Status = CDVD_STATUS_PAUSE;
cdvd.nextSectorsBuffered = 0; cdvd.nextSectorsBuffered = 0;
cdvd.triggerDataReady = true;
CDVDSECTORREADY_INT(cdvd.ReadTime); CDVDSECTORREADY_INT(cdvd.ReadTime);
break; break;
@ -1899,11 +1894,9 @@ static void cdvdWrite04(u8 rt)
cdvdReadKey(arg0, arg1, arg2, cdvd.Key); cdvdReadKey(arg0, arg1, arg2, cdvd.Key);
cdvd.KeyXor = 0x00; cdvd.KeyXor = 0x00;
cdvdSetIrq(); cdvdSetIrq();
cdvd.nCommand = 0;
//After reading the key it needs to go back to buffer the next sector //After reading the key it needs to go back to buffer the next sector
cdvd.Status = CDVD_STATUS_PAUSE; cdvd.Status = CDVD_STATUS_PAUSE;
cdvd.nextSectorsBuffered = 0; cdvd.nextSectorsBuffered = 0;
cdvd.triggerDataReady = true;
CDVDSECTORREADY_INT(cdvd.ReadTime); CDVDSECTORREADY_INT(cdvd.ReadTime);
} }
break; break;
@ -1911,13 +1904,11 @@ static void cdvdWrite04(u8 rt)
case N_CD_CHG_SPDL_CTRL: // CdChgSpdlCtrl case N_CD_CHG_SPDL_CTRL: // CdChgSpdlCtrl
Console.WriteLn("sceCdChgSpdlCtrl(%d)", cdvd.Param[0]); Console.WriteLn("sceCdChgSpdlCtrl(%d)", cdvd.Param[0]);
cdvdSetIrq(); cdvdSetIrq();
cdvd.nCommand = 0;
break; break;
default: default:
Console.Warning("NCMD Unknown %x", rt); Console.Warning("NCMD Unknown %x", rt);
cdvdSetIrq(); cdvdSetIrq();
cdvd.nCommand = 0;
break; break;
} }
cdvd.ParamP = 0; cdvd.ParamP = 0;
@ -1963,18 +1954,12 @@ static __fi void cdvdWrite07(u8 rt) // BREAK
cdvd.Readed = 0; cdvd.Readed = 0;
cdvd.Reading = 0; cdvd.Reading = 0;
cdvd.Status = CDVD_STATUS_STOP; cdvd.Status = CDVD_STATUS_STOP;
//cdvd.nCommand = 0;
} }
static __fi void cdvdWrite08(u8 rt) static __fi void cdvdWrite08(u8 rt)
{ // INTR_STAT { // INTR_STAT
CDVD_LOG("cdvdWrite08(IntrReason) = ACK(%x)", rt); CDVD_LOG("cdvdWrite08(IntrReason) = ACK(%x)", rt);
cdvd.PwOff &= ~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) static __fi void cdvdWrite0A(u8 rt)

View File

@ -148,12 +148,12 @@ struct cdvdStruct
u8 TrayTimeout; u8 TrayTimeout;
u8 Action; // the currently scheduled emulated action u8 Action; // the currently scheduled emulated action
u32 SeekToSector; // Holds the destination sector during seek operations. 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) 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 Spinning; // indicates if the Cdvd is spinning or needs a spinup delay
bool mediaChanged; bool mediaChanged;
cdvdTrayTimer Tray; cdvdTrayTimer Tray;
u8 nextSectorsBuffered; u8 nextSectorsBuffered;
bool triggerDataReady;
}; };
extern cdvdStruct cdvd; 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 enum CdvdIrqId
{ {
Irq_None = 0, Irq_None = 0,
@ -49,6 +51,16 @@ enum CdvdIrqId
Irq_NotReady 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 /* Cdvd.Status bits and their meaning
0x0 = Stop 0x0 = Stop

View File

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