X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libpcsxcore%2Fcdrom.c;h=3c016dfd2be1c8fd7c2fc35f3b1e77cb14a085bb;hb=f5450cfbaf8651524f23579832ddb5bc08fe545a;hp=07b13649c49c04888de27058480c3277a36e9f10;hpb=e9b207f1b9c79001aaa75abfc4cec353f006a57d;p=pcsx_rearmed.git diff --git a/libpcsxcore/cdrom.c b/libpcsxcore/cdrom.c index 07b13649..3c016dfd 100644 --- a/libpcsxcore/cdrom.c +++ b/libpcsxcore/cdrom.c @@ -45,10 +45,11 @@ //#define CDR_LOG_CMD_IRQ static struct { - unsigned char OCUP; - unsigned char Reg1Mode; + // unused members maintain savesate compatibility + unsigned char unused0; + unsigned char unused1; unsigned char Reg2; - unsigned char CmdProcess; + unsigned char unused2; unsigned char Ctrl; unsigned char Stat; @@ -62,7 +63,7 @@ static struct { unsigned char Absolute[3]; } subq; unsigned char TrackChanged; - unsigned char pad1[3]; + unsigned char unused3[3]; unsigned int freeze_ver; unsigned char Prev[4]; @@ -94,18 +95,19 @@ static struct { xa_decode_t Xa; - int Init; + u32 unused4; - u16 Irq; - u8 IrqRepeated; - u32 eCycle; + u16 CmdInProgress; + u8 Irq1Pending; + u8 unused5; + u32 unused6; - u8 pad2; + u8 unused7; u8 DriveState; u8 FastForward; u8 FastBackward; - u8 pad; + u8 unused8; u8 AttenuatorLeftToLeft, AttenuatorLeftToRight; u8 AttenuatorRightToRight, AttenuatorRightToLeft; @@ -242,11 +244,15 @@ static void sec2msf(unsigned int s, u8 *msf) { } // cdrPlaySeekReadInterrupt -#define CDRPLAYSEEKREAD_INT(eCycle) { \ +#define CDRPLAYSEEKREAD_INT(eCycle, isFirst) { \ + u32 e_ = eCycle; \ psxRegs.interrupt |= (1 << PSXINT_CDREAD); \ - psxRegs.intCycle[PSXINT_CDREAD].cycle = eCycle; \ - psxRegs.intCycle[PSXINT_CDREAD].sCycle = psxRegs.cycle; \ - new_dyna_set_event(PSXINT_CDREAD, eCycle); \ + if (isFirst) \ + psxRegs.intCycle[PSXINT_CDREAD].sCycle = psxRegs.cycle; \ + else \ + psxRegs.intCycle[PSXINT_CDREAD].sCycle += psxRegs.intCycle[PSXINT_CDREAD].cycle; \ + psxRegs.intCycle[PSXINT_CDREAD].cycle = e_; \ + new_dyna_set_event_abs(PSXINT_CDREAD, psxRegs.intCycle[PSXINT_CDREAD].sCycle + e_); \ } // cdrLidSeekInterrupt @@ -286,6 +292,7 @@ static void setIrq(int log_cmd) psxHu32ref(0x1070) |= SWAP32((u32)0x4); #ifdef CDR_LOG_CMD_IRQ + if (cdr.Stat) { int i; SysPrintf("CDR IRQ=%d cmd %02x stat %02x: ", @@ -477,23 +484,6 @@ static void ReadTrack(const u8 *time) { cdr.subq.Absolute[0], cdr.subq.Absolute[1], cdr.subq.Absolute[2]); } -static void AddIrqQueue(unsigned short irq, unsigned long ecycle) { - if (cdr.Irq != 0) { - if (irq == cdr.Irq || irq + 0x100 == cdr.Irq) { - cdr.IrqRepeated = 1; - CDR_INT(ecycle); - return; - } - - CDR_LOG_I("cdr: override cmd %02x -> %02x\n", cdr.Irq, irq); - } - - cdr.Irq = irq; - cdr.eCycle = ecycle; - - CDR_INT(ecycle); -} - static void cdrPlayInterrupt_Autopause() { u32 abs_lev_max = 0; @@ -588,17 +578,15 @@ void cdrPlaySeekReadInterrupt(void) if (!cdr.Play && (cdr.StatP & STATUS_SEEK)) { if (cdr.Stat) { CDR_LOG_I("cdrom: seek stat hack\n"); - CDRPLAYSEEKREAD_INT(0x1000); + CDRPLAYSEEKREAD_INT(0x1000, 1); return; } SetResultSize(1); cdr.StatP |= STATUS_ROTATING; SetPlaySeekRead(cdr.StatP, 0); cdr.Result[0] = cdr.StatP; - if (cdr.Irq == 0) { - cdr.Stat = Complete; - setIrq(0x202); - } + cdr.Stat = Complete; + setIrq(0x202); Find_CurTrack(cdr.SetSectorPlay); ReadTrack(cdr.SetSectorPlay); @@ -621,13 +609,13 @@ void cdrPlaySeekReadInterrupt(void) CDR_readCDDA(cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2], (u8 *)read_buf); } - if (!cdr.Irq && !cdr.Stat && (cdr.Mode & (MODE_AUTOPAUSE|MODE_REPORT))) + if (!cdr.Stat && (cdr.Mode & (MODE_AUTOPAUSE|MODE_REPORT))) cdrPlayInterrupt_Autopause(); - if (CDR_readCDDA && !cdr.Muted && !Config.Cdda) { + if (!cdr.Muted && !Config.Cdda) { cdrAttenuate(read_buf, CD_FRAMESIZE_RAW / 4, 1); - if (SPU_playCDDAchannel) - SPU_playCDDAchannel(read_buf, CD_FRAMESIZE_RAW); + SPU_playCDDAchannel(read_buf, CD_FRAMESIZE_RAW, psxRegs.cycle, cdr.FirstSector); + cdr.FirstSector = 0; } cdr.SetSectorPlay[2]++; @@ -640,26 +628,25 @@ void cdrPlaySeekReadInterrupt(void) } } - CDRPLAYSEEKREAD_INT(cdReadTime); - // update for CdlGetlocP/autopause generate_subq(cdr.SetSectorPlay); + + CDRPLAYSEEKREAD_INT(cdReadTime, 0); } void cdrInterrupt(void) { - u16 Irq = cdr.Irq; int no_busy_error = 0; int start_rotating = 0; int error = 0; - int delay; unsigned int seekTime = 0; + u32 second_resp_time = 0; + u8 ParamC; u8 set_loc[3]; + u16 Cmd; int i; - // Reschedule IRQ if (cdr.Stat) { - CDR_LOG_I("cdrom: stat hack: %02x %x\n", cdr.Irq, cdr.Stat); - CDR_INT(0x1000); + CDR_LOG_I("cdrom: cmd %02x with irqstat %x\n", cdr.CmdInProgress, cdr.Stat); return; } @@ -670,17 +657,16 @@ void cdrInterrupt(void) { cdr.Result[0] = cdr.StatP; cdr.Stat = Acknowledge; - if (cdr.IrqRepeated) { - cdr.IrqRepeated = 0; - if (cdr.eCycle > psxRegs.cycle) { - CDR_INT(cdr.eCycle); - goto finish; - } - } + Cmd = cdr.CmdInProgress; + cdr.CmdInProgress = 0; + ParamC = cdr.ParamC; - cdr.Irq = 0; + if (Cmd < 0x100) { + cdr.Cmd = 0; + cdr.ParamC = 0; + } - switch (Irq) { + switch (Cmd) { case CdlNop: if (cdr.DriveState != DRIVESTATE_LID_OPEN) cdr.StatP &= ~STATUS_SHELLOPEN; @@ -718,7 +704,7 @@ void cdrInterrupt(void) { // BIOS CD Player // - Pause player, hit Track 01/02/../xx (Setloc issued!!) - if (cdr.ParamC != 0 && cdr.Param[0] != 0) { + if (ParamC != 0 && cdr.Param[0] != 0) { int track = btoi( cdr.Param[0] ); if (track <= cdr.ResultTN[1]) @@ -756,6 +742,7 @@ void cdrInterrupt(void) { Find_CurTrack(cdr.SetSectorPlay); ReadTrack(cdr.SetSectorPlay); cdr.TrackChanged = FALSE; + cdr.FirstSector = 1; if (!Config.Cdda) CDR_play(cdr.SetSectorPlay); @@ -765,7 +752,7 @@ void cdrInterrupt(void) { // BIOS player - set flag again cdr.Play = TRUE; - CDRPLAYSEEKREAD_INT(cdReadTime + seekTime); + CDRPLAYSEEKREAD_INT(cdReadTime + seekTime, 1); start_rotating = 1; break; @@ -791,7 +778,7 @@ void cdrInterrupt(void) { error = ERROR_INVALIDARG; goto set_error; } - AddIrqQueue(CdlStandby + 0x100, cdReadTime * 125 / 2); + second_resp_time = cdReadTime * 125 / 2; start_rotating = 1; break; @@ -814,12 +801,11 @@ void cdrInterrupt(void) { SetPlaySeekRead(cdr.StatP, 0); cdr.StatP &= ~STATUS_ROTATING; - delay = 0x800; + second_resp_time = 0x800; if (cdr.DriveState == DRIVESTATE_STANDBY) - delay = cdReadTime * 30 / 2; + second_resp_time = cdReadTime * 30 / 2; cdr.DriveState = DRIVESTATE_STOPPED; - AddIrqQueue(CdlStop + 0x100, delay); break; case CdlStop + 0x100: @@ -846,13 +832,12 @@ void cdrInterrupt(void) { * */ if (!(cdr.StatP & (STATUS_PLAY | STATUS_READ))) { - delay = 7000; + second_resp_time = 7000; } else { - delay = (((cdr.Mode & MODE_SPEED) ? 2 : 1) * (1000000)); + second_resp_time = (((cdr.Mode & MODE_SPEED) ? 2 : 1) * 1000000); } - AddIrqQueue(CdlPause + 0x100, delay); SetPlaySeekRead(cdr.StatP, 0); cdr.Ctrl |= 0x80; break; @@ -867,7 +852,7 @@ void cdrInterrupt(void) { SetPlaySeekRead(cdr.StatP, 0); cdr.Muted = FALSE; cdr.Mode = 0x20; /* This fixes This is Football 2, Pooh's Party lockups */ - AddIrqQueue(CdlReset + 0x100, 4100000); + second_resp_time = 4100000; no_busy_error = 1; start_rotating = 1; break; @@ -890,6 +875,8 @@ void cdrInterrupt(void) { break; case CdlSetmode: + CDR_LOG("cdrWrite1() Log: Setmode %x\n", cdr.Param[0]); + cdr.Mode = cdr.Param[0]; no_busy_error = 1; break; @@ -915,7 +902,7 @@ void cdrInterrupt(void) { case CdlReadT: // SetSession? // really long - AddIrqQueue(CdlReadT + 0x100, cdReadTime * 290 / 4); + second_resp_time = cdReadTime * 290 / 4; start_rotating = 1; break; @@ -973,7 +960,7 @@ void cdrInterrupt(void) { Rockman X5 = 0.5-4x - fix capcom logo */ - CDRPLAYSEEKREAD_INT(cdReadTime + seekTime); + CDRPLAYSEEKREAD_INT(cdReadTime + seekTime, 1); start_rotating = 1; break; @@ -996,7 +983,7 @@ void cdrInterrupt(void) { break; case CdlID: - AddIrqQueue(CdlID + 0x100, 20480); + second_resp_time = 20480; break; case CdlID + 0x100: @@ -1040,7 +1027,7 @@ void cdrInterrupt(void) { break; case CdlReadToc: - AddIrqQueue(CdlReadToc + 0x100, cdReadTime * 180 / 4); + second_resp_time = cdReadTime * 180 / 4; no_busy_error = 1; start_rotating = 1; break; @@ -1071,14 +1058,14 @@ void cdrInterrupt(void) { // - fixes new game ReadTrack(cdr.SetSectorPlay); - CDRPLAYSEEKREAD_INT(((cdr.Mode & 0x80) ? (cdReadTime) : cdReadTime * 2) + seekTime); + CDRPLAYSEEKREAD_INT(((cdr.Mode & 0x80) ? (cdReadTime) : cdReadTime * 2) + seekTime, 1); SetPlaySeekRead(cdr.StatP, STATUS_SEEK); start_rotating = 1; break; case CdlSync: default: - CDR_LOG_I("Invalid command: %02x\n", Irq); + CDR_LOG_I("Invalid command: %02x\n", Cmd); error = ERROR_INVALIDCMD; // FALLTHROUGH @@ -1108,9 +1095,16 @@ void cdrInterrupt(void) { } } -finish: - setIrq(Irq); - cdr.ParamC = 0; + if (second_resp_time) { + cdr.CmdInProgress = Cmd | 0x100; + CDR_INT(second_resp_time); + } + else if (cdr.Cmd && cdr.Cmd != (Cmd & 0xff)) { + cdr.CmdInProgress = cdr.Cmd; + CDR_LOG_I("cdrom: cmd %02x came before %02x finished\n", cdr.Cmd, Cmd); + } + + setIrq(Cmd); } #ifdef HAVE_ARMV7 @@ -1161,47 +1155,59 @@ void cdrAttenuate(s16 *buf, int samples, int stereo) } } -static void cdrReadInterrupt(void) +static void cdrReadInterruptSetResult(unsigned char result) { - u8 *buf; - - if (cdr.Irq || cdr.Stat) { - CDR_LOG_I("cdrom: read stat hack %02x %x\n", cdr.Irq, cdr.Stat); - CDRPLAYSEEKREAD_INT(2048); + if (cdr.Stat) { + CDR_LOG_I("cdrom: %d:%02d:%02d irq miss, cmd=%02x irqstat=%02x\n", + cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2], + cdr.CmdInProgress, cdr.Stat); + cdr.Irq1Pending = result; return; } - - cdr.OCUP = 1; SetResultSize(1); + cdr.Result[0] = result; + cdr.Stat = (result & STATUS_ERROR) ? DiskError : DataReady; + setIrq(0x203); +} + +static void cdrUpdateTransferBuf(const u8 *buf) +{ + if (!buf) + return; + memcpy(cdr.Transfer, buf, DATA_SIZE); + CheckPPFCache(cdr.Transfer, cdr.Prev[0], cdr.Prev[1], cdr.Prev[2]); + CDR_LOG("cdr.Transfer %x:%x:%x\n", cdr.Transfer[0], cdr.Transfer[1], cdr.Transfer[2]); + cdr.Readed = 0; +} + +static void cdrReadInterrupt(void) +{ + u8 *buf = NULL, *hdr; + SetPlaySeekRead(cdr.StatP, STATUS_READ | STATUS_ROTATING); - cdr.Result[0] = cdr.StatP; ReadTrack(cdr.SetSectorPlay); - - buf = CDR_getBuffer(); + if (cdr.NoErr) + buf = CDR_getBuffer(); if (buf == NULL) cdr.NoErr = 0; if (!cdr.NoErr) { CDR_LOG_I("cdrReadInterrupt() Log: err\n"); memset(cdr.Transfer, 0, DATA_SIZE); - cdr.Stat = DiskError; - cdr.Result[0] |= STATUS_ERROR; - setIrq(0x205); + cdrReadInterruptSetResult(cdr.StatP | STATUS_ERROR); return; } - memcpy(cdr.Transfer, buf, DATA_SIZE); - CheckPPFCache(cdr.Transfer, cdr.Prev[0], cdr.Prev[1], cdr.Prev[2]); - - - CDR_LOG("cdrReadInterrupt() Log: cdr.Transfer %x:%x:%x\n", cdr.Transfer[0], cdr.Transfer[1], cdr.Transfer[2]); + if (!cdr.Irq1Pending) + cdrUpdateTransferBuf(buf); if ((!cdr.Muted) && (cdr.Mode & MODE_STRSND) && (!Config.Xa) && (cdr.FirstSector != -1)) { // CD-XA + hdr = buf + 4; // Firemen 2: Multi-XA files - briefings, cutscenes if( cdr.FirstSector == 1 && (cdr.Mode & MODE_SF)==0 ) { - cdr.File = cdr.Transfer[4 + 0]; - cdr.Channel = cdr.Transfer[4 + 1]; + cdr.File = hdr[0]; + cdr.Channel = hdr[1]; } /* Gameblabla @@ -1209,19 +1215,26 @@ static void cdrReadInterrupt(void) * Fixes missing audio in Blue's Clues : Blue's Big Musical. (Should also fix Taxi 2) * TODO : Check if this is the proper behaviour. * */ - if((cdr.Transfer[4 + 2] & 0x4) && - (cdr.Transfer[4 + 1] == cdr.Channel) && - (cdr.Transfer[4 + 0] == cdr.File) && cdr.Channel != 255) { - int ret = xa_decode_sector(&cdr.Xa, cdr.Transfer+4, cdr.FirstSector); + if ((hdr[2] & 0x4) && hdr[0] == cdr.File && hdr[1] == cdr.Channel && cdr.Channel != 255) { + int ret = xa_decode_sector(&cdr.Xa, buf + 4, cdr.FirstSector); if (!ret) { cdrAttenuate(cdr.Xa.pcm, cdr.Xa.nsamples, cdr.Xa.stereo); - SPU_playADPCMchannel(&cdr.Xa); + SPU_playADPCMchannel(&cdr.Xa, psxRegs.cycle, cdr.FirstSector); cdr.FirstSector = 0; } else cdr.FirstSector = -1; } } + /* + Croc 2: $40 - only FORM1 (*) + Judge Dredd: $C8 - only FORM1 (*) + Sim Theme Park - no adpcm at all (zero) + */ + + if (!(cdr.Mode & MODE_STRSND) || !(buf[4+2] & 0x4)) + cdrReadInterruptSetResult(cdr.StatP); + cdr.SetSectorPlay[2]++; if (cdr.SetSectorPlay[2] == 75) { cdr.SetSectorPlay[2] = 0; @@ -1232,23 +1245,31 @@ static void cdrReadInterrupt(void) } } - cdr.Readed = 0; - - CDRPLAYSEEKREAD_INT((cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime); + if (!cdr.Irq1Pending) { + // update for CdlGetlocP + ReadTrack(cdr.SetSectorPlay); + } - /* - Croc 2: $40 - only FORM1 (*) - Judge Dredd: $C8 - only FORM1 (*) - Sim Theme Park - no adpcm at all (zero) - */ + CDRPLAYSEEKREAD_INT((cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime, 0); +} - if (!(cdr.Mode & MODE_STRSND) || !(cdr.Transfer[4+2] & 0x4)) { - cdr.Stat = DataReady; - setIrq(0x203); +static void doMissedIrqs(void) +{ + if (cdr.Irq1Pending) + { + // hand out the "newest" sector, according to nocash + cdrUpdateTransferBuf(CDR_getBuffer()); + CDR_LOG_I("cdrom: %x:%02x:%02x loaded on ack\n", + cdr.Transfer[0], cdr.Transfer[1], cdr.Transfer[2]); + SetResultSize(1); + cdr.Result[0] = cdr.Irq1Pending; + cdr.Stat = (cdr.Irq1Pending & STATUS_ERROR) ? DiskError : DataReady; + cdr.Irq1Pending = 0; + setIrq(0x205); + return; } - - // update for CdlGetlocP - ReadTrack(cdr.SetSectorPlay); + if (!(psxRegs.interrupt & (1 << PSXINT_CDR)) && cdr.CmdInProgress) + CDR_INT(256); } /* @@ -1268,10 +1289,7 @@ unsigned char cdrRead0(void) { else cdr.Ctrl &= ~0x20; - if (cdr.OCUP) - cdr.Ctrl |= 0x40; -// else -// cdr.Ctrl &= ~0x40; + cdr.Ctrl |= 0x40; // data fifo not empty // What means the 0x10 and the 0x08 bits? I only saw it used by the bios cdr.Ctrl |= 0x18; @@ -1315,9 +1333,6 @@ void cdrWrite1(unsigned char rt) { return; } - cdr.Cmd = rt; - cdr.OCUP = 0; - #ifdef CDR_LOG_CMD_IRQ SysPrintf("CD1 write: %x (%s)", rt, CmdName[rt]); if (cdr.ParamC) { @@ -1333,16 +1348,20 @@ void cdrWrite1(unsigned char rt) { cdr.ResultReady = 0; cdr.Ctrl |= 0x80; - // cdr.Stat = NoIntr; - AddIrqQueue(cdr.Cmd, 0x800); - - switch (cdr.Cmd) { - case CdlSetmode: - CDR_LOG("cdrWrite1() Log: Setmode %x\n", cdr.Param[0]); - cdr.Mode = cdr.Param[0]; - break; + if (!cdr.CmdInProgress) { + cdr.CmdInProgress = rt; + // should be something like 12k + controller delays + CDR_INT(5000); + } + else { + CDR_LOG_I("cdr: cmd while busy: %02x, prev %02x, busy %02x\n", + rt, cdr.Cmd, cdr.CmdInProgress); + if (cdr.CmdInProgress < 0x100) // no pending 2nd response + cdr.CmdInProgress = rt; } + + cdr.Cmd = rt; } unsigned char cdrRead2(void) { @@ -1398,10 +1417,15 @@ void cdrWrite3(unsigned char rt) { case 0: break; // transfer case 1: +#ifdef CDR_LOG_CMD_IRQ + if (cdr.Stat & rt) + SysPrintf("ack %02x\n", cdr.Stat & rt); +#endif cdr.Stat &= ~rt; if (rt & 0x40) cdr.ParamC = 0; + doMissedIrqs(); return; case 2: cdr.AttenuatorLeftToRightT = rt; @@ -1409,7 +1433,7 @@ void cdrWrite3(unsigned char rt) { case 3: if (rt & 0x20) { memcpy(&cdr.AttenuatorLeftToLeft, &cdr.AttenuatorLeftToLeftT, 4); - CDR_LOG_I("CD-XA Volume: %02x %02x | %02x %02x\n", + CDR_LOG("CD-XA Volume: %02x %02x | %02x %02x\n", cdr.AttenuatorLeftToLeft, cdr.AttenuatorLeftToRight, cdr.AttenuatorRightToLeft, cdr.AttenuatorRightToRight); } @@ -1447,7 +1471,7 @@ void psxDma3(u32 madr, u32 bcr, u32 chcr) { case 0x11000000: case 0x11400100: if (cdr.Readed == 0) { - CDR_LOG("psxDma3() Log: *** DMA 3 *** NOT READY\n"); + CDR_LOG_I("psxDma3() Log: *** DMA 3 *** NOT READY\n"); break; } @@ -1587,7 +1611,7 @@ int cdrFreeze(void *f, int Mode) { if (!Config.Cdda) CDR_play(cdr.SetSectorPlay); if (psxRegs.interrupt & (1 << PSXINT_CDRPLAY_OLD)) - CDRPLAYSEEKREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime); + CDRPLAYSEEKREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime, 1); } if ((cdr.freeze_ver & 0xffffff00) != 0x63647200) {