static void psxRcntSet(void) { s32 countToUpdate; u32 i; psxNextsCounter = psxRegs.cycle; psxNextCounter = 0x7fffffff; #ifdef USE_EXTRA_IO_CYCLES // CHUI: Añado ResetIoCycle para permite que en el proximo salto entre en psxBranchTest ResetIoCycle(); #endif for( i = 0; i < CounterQuantity; ++i ) { countToUpdate = rcnts[i].cycle - (psxNextsCounter - rcnts[i].cycleStart); if( countToUpdate < 0 ) { psxNextCounter = 0; break; } if( countToUpdate < (s32)psxNextCounter ) { psxNextCounter = countToUpdate; } } #ifndef USE_EXTRA_IO_CYCLES { const u32 value = psxRegs.cycle+psxNextCounter; if (psxRegs.io_cycle_counter>value) psxRegs.io_cycle_counter=value; } #endif }
void cdrInterrupt() { u16 Irq = cdr.Irq; int no_busy_error = 0; int start_rotating = 0; int error = 0; int delay; // Reschedule IRQ if (cdr.Stat) { CDR_LOG_I("cdrom: stat hack: %02x %x\n", cdr.Irq, cdr.Stat); CDR_INT(0x1000); return; } cdr.Ctrl &= ~0x80; // default response SetResultSize(1); 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; } } cdr.Irq = 0; switch (Irq) { case CdlSync: // TOOD: sometimes/always return error? break; case CdlNop: if (cdr.DriveState != DRIVESTATE_LID_OPEN) cdr.StatP &= ~STATUS_SHELLOPEN; no_busy_error = 1; break; case CdlSetloc: break; do_CdlPlay: case CdlPlay: StopCdda(); if (cdr.Seeked == SEEK_PENDING) { // XXX: wrong, should seek instead.. cdr.Seeked = SEEK_DONE; } if (cdr.SetlocPending) { memcpy(cdr.SetSectorPlay, cdr.SetSector, 4); cdr.SetlocPending = 0; } // BIOS CD Player // - Pause player, hit Track 01/02/../xx (Setloc issued!!) if (cdr.ParamC == 0 || cdr.Param[0] == 0) { CDR_LOG("PLAY Resume @ %d:%d:%d\n", cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2]); } else { int track = btoi( cdr.Param[0] ); if (track <= cdr.ResultTN[1]) cdr.CurTrack = track; CDR_LOG("PLAY track %d\n", cdr.CurTrack); if (CDR_getTD((u8)cdr.CurTrack, cdr.ResultTD) != -1) { cdr.SetSectorPlay[0] = cdr.ResultTD[2]; cdr.SetSectorPlay[1] = cdr.ResultTD[1]; cdr.SetSectorPlay[2] = cdr.ResultTD[0]; } } /* Rayman: detect track changes - fixes logo freeze Twisted Metal 2: skip PREGAP + starting accurate SubQ - plays tracks without retry play Wild 9: skip PREGAP + starting accurate SubQ - plays tracks without retry play */ Find_CurTrack(cdr.SetSectorPlay); ReadTrack(cdr.SetSectorPlay); cdr.TrackChanged = FALSE; if (!Config.Cdda) CDR_play(cdr.SetSectorPlay); // Vib Ribbon: gameplay checks flag cdr.StatP &= ~STATUS_SEEK; cdr.Result[0] = cdr.StatP; cdr.StatP |= STATUS_PLAY; // BIOS player - set flag again cdr.Play = TRUE; CDRMISC_INT( cdReadTime ); start_rotating = 1; break; case CdlForward: // TODO: error 80 if stopped cdr.Stat = Complete; // GameShark CD Player: Calls 2x + Play 2x if( cdr.FastForward == 0 ) cdr.FastForward = 2; else cdr.FastForward++; cdr.FastBackward = 0; break; case CdlBackward: cdr.Stat = Complete; // GameShark CD Player: Calls 2x + Play 2x if( cdr.FastBackward == 0 ) cdr.FastBackward = 2; else cdr.FastBackward++; cdr.FastForward = 0; break; case CdlStandby: if (cdr.DriveState != DRIVESTATE_STOPPED) { error = ERROR_INVALIDARG; goto set_error; } AddIrqQueue(CdlStandby + 0x100, cdReadTime * 125 / 2); start_rotating = 1; break; case CdlStandby + 0x100: cdr.Stat = Complete; break; case CdlStop: if (cdr.Play) { // grab time for current track CDR_getTD((u8)(cdr.CurTrack), cdr.ResultTD); cdr.SetSectorPlay[0] = cdr.ResultTD[2]; cdr.SetSectorPlay[1] = cdr.ResultTD[1]; cdr.SetSectorPlay[2] = cdr.ResultTD[0]; } StopCdda(); StopReading(); delay = 0x800; if (cdr.DriveState == DRIVESTATE_STANDBY) delay = cdReadTime * 30 / 2; cdr.DriveState = DRIVESTATE_STOPPED; AddIrqQueue(CdlStop + 0x100, delay); break; case CdlStop + 0x100: cdr.StatP &= ~STATUS_ROTATING; cdr.Result[0] = cdr.StatP; cdr.Stat = Complete; break; case CdlPause: /* Gundam Battle Assault 2: much slower (*) - Fixes boot, gameplay Hokuto no Ken 2: slower - Fixes intro + subtitles InuYasha - Feudal Fairy Tale: slower - Fixes battles */ AddIrqQueue(CdlPause + 0x100, cdReadTime * 3); cdr.Ctrl |= 0x80; break; case CdlPause + 0x100: cdr.StatP &= ~STATUS_READ; cdr.Result[0] = cdr.StatP; cdr.Stat = Complete; break; case CdlInit: AddIrqQueue(CdlInit + 0x100, cdReadTime * 6); no_busy_error = 1; start_rotating = 1; break; case CdlInit + 0x100: cdr.Stat = Complete; break; case CdlMute: cdr.Muted = TRUE; break; case CdlDemute: cdr.Muted = FALSE; break; case CdlSetfilter: cdr.File = cdr.Param[0]; cdr.Channel = cdr.Param[1]; break; case CdlSetmode: no_busy_error = 1; break; case CdlGetmode: SetResultSize(6); cdr.Result[1] = cdr.Mode; cdr.Result[2] = cdr.File; cdr.Result[3] = cdr.Channel; cdr.Result[4] = 0; cdr.Result[5] = 0; no_busy_error = 1; break; case CdlGetlocL: SetResultSize(8); memcpy(cdr.Result, cdr.Transfer, 8); break; case CdlGetlocP: SetResultSize(8); memcpy(&cdr.Result, &cdr.subq, 8); if (!cdr.Play && !cdr.Reading) cdr.Result[1] = 0; // HACK? break; case CdlReadT: // SetSession? // really long AddIrqQueue(CdlReadT + 0x100, cdReadTime * 290 / 4); start_rotating = 1; break; case CdlReadT + 0x100: cdr.Stat = Complete; break; case CdlGetTN: SetResultSize(3); if (CDR_getTN(cdr.ResultTN) == -1) { cdr.Stat = DiskError; cdr.Result[0] |= STATUS_ERROR; } else { cdr.Stat = Acknowledge; cdr.Result[1] = itob(cdr.ResultTN[0]); cdr.Result[2] = itob(cdr.ResultTN[1]); } break; case CdlGetTD: cdr.Track = btoi(cdr.Param[0]); SetResultSize(4); if (CDR_getTD(cdr.Track, cdr.ResultTD) == -1) { cdr.Stat = DiskError; cdr.Result[0] |= STATUS_ERROR; } else { cdr.Stat = Acknowledge; cdr.Result[0] = cdr.StatP; cdr.Result[1] = itob(cdr.ResultTD[2]); cdr.Result[2] = itob(cdr.ResultTD[1]); cdr.Result[3] = itob(cdr.ResultTD[0]); } break; case CdlSeekL: case CdlSeekP: StopCdda(); StopReading(); cdr.StatP |= STATUS_SEEK; /* Crusaders of Might and Magic = 0.5x-4x - fix cutscene speech start Eggs of Steel = 2x-? - fix new game Medievil = ?-4x - fix cutscene speech Rockman X5 = 0.5-4x - fix capcom logo */ CDRMISC_INT(cdr.Seeked == SEEK_DONE ? 0x800 : cdReadTime * 4); cdr.Seeked = SEEK_PENDING; start_rotating = 1; break; case CdlTest: switch (cdr.Param[0]) { case 0x20: // System Controller ROM Version SetResultSize(4); memcpy(cdr.Result, Test20, 4); break; case 0x22: SetResultSize(8); memcpy(cdr.Result, Test22, 4); break; case 0x23: case 0x24: SetResultSize(8); memcpy(cdr.Result, Test23, 4); break; } no_busy_error = 1; break; case CdlID: AddIrqQueue(CdlID + 0x100, 20480); break; case CdlID + 0x100: SetResultSize(8); cdr.Result[0] = cdr.StatP; cdr.Result[1] = 0; cdr.Result[2] = 0; cdr.Result[3] = 0; // 0x10 - audio | 0x40 - disk missing | 0x80 - unlicensed if (CDR_getStatus(&stat) == -1 || stat.Type == 0 || stat.Type == 0xff) { cdr.Result[1] = 0xc0; } else { if (stat.Type == 2) cdr.Result[1] |= 0x10; if (CdromId[0] == '\0') cdr.Result[1] |= 0x80; } cdr.Result[0] |= (cdr.Result[1] >> 4) & 0x08; strncpy((char *)&cdr.Result[4], "PCSX", 4); cdr.Stat = Complete; break; case CdlReset: // yes, it really sets STATUS_SHELLOPEN cdr.StatP |= STATUS_SHELLOPEN; cdr.DriveState = DRIVESTATE_RESCAN_CD; CDRLID_INT(20480); no_busy_error = 1; start_rotating = 1; break; case CdlGetQ: // TODO? CDR_LOG_I("got CdlGetQ\n"); break; case CdlReadToc: AddIrqQueue(CdlReadToc + 0x100, cdReadTime * 180 / 4); no_busy_error = 1; start_rotating = 1; break; case CdlReadToc + 0x100: cdr.Stat = Complete; no_busy_error = 1; break; case CdlReadN: case CdlReadS: if (cdr.SetlocPending) { memcpy(cdr.SetSectorPlay, cdr.SetSector, 4); cdr.SetlocPending = 0; } Find_CurTrack(cdr.SetSectorPlay); if ((cdr.Mode & MODE_CDDA) && cdr.CurTrack > 1) // Read* acts as play for cdda tracks in cdda mode goto do_CdlPlay; cdr.Reading = 1; cdr.FirstSector = 1; // Fighting Force 2 - update subq time immediately // - fixes new game ReadTrack(cdr.SetSectorPlay); // Crusaders of Might and Magic - update getlocl now // - fixes cutscene speech { u8 *buf = CDR_getBuffer(); if (buf != NULL) memcpy(cdr.Transfer, buf, 8); } /* Duke Nukem: Land of the Babes - seek then delay read for one frame - fixes cutscenes C-12 - Final Resistance - doesn't like seek */ if (cdr.Seeked != SEEK_DONE) { cdr.StatP |= STATUS_SEEK; cdr.StatP &= ~STATUS_READ; // Crusaders of Might and Magic - use short time // - fix cutscene speech (startup) // ??? - use more accurate seek time later CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime * 1); } else { cdr.StatP |= STATUS_READ; cdr.StatP &= ~STATUS_SEEK; CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime * 1); } cdr.Result[0] = cdr.StatP; start_rotating = 1; break; default: CDR_LOG_I("Invalid command: %02x\n", Irq); error = ERROR_INVALIDCMD; // FALLTHROUGH set_error: SetResultSize(2); cdr.Result[0] = cdr.StatP | STATUS_ERROR; cdr.Result[1] = error; cdr.Stat = DiskError; break; } if (cdr.DriveState == DRIVESTATE_STOPPED && start_rotating) { cdr.DriveState = DRIVESTATE_STANDBY; cdr.StatP |= STATUS_ROTATING; } if (!no_busy_error) { switch (cdr.DriveState) { case DRIVESTATE_LID_OPEN: case DRIVESTATE_RESCAN_CD: case DRIVESTATE_PREPARE_CD: SetResultSize(2); cdr.Result[0] = cdr.StatP | STATUS_ERROR; cdr.Result[1] = ERROR_NOTREADY; cdr.Stat = DiskError; break; } } finish: setIrq(); cdr.ParamC = 0; #ifdef CDR_LOG_CMD_IRQ { int i; SysPrintf("CDR IRQ %d cmd %02x stat %02x: ", !!(cdr.Stat & cdr.Reg2), Irq, cdr.Stat); for (i = 0; i < cdr.ResultC; i++) SysPrintf("%02x ", cdr.Result[i]); SysPrintf("\n"); } #endif //senquack - Copy/pasted CHUI's ResetIoCycle() call into this new function // TODO: Are these really beneficial/necessary? // CHUI: Añado ResetIoCycle para permite que en el proximo salto entre en psxBranchTest ResetIoCycle(); }
// also handles seek void cdrPlayInterrupt() { if (cdr.Seeked == SEEK_PENDING) { if (cdr.Stat) { CDR_LOG_I("cdrom: seek stat hack\n"); CDRMISC_INT(0x1000); return; } SetResultSize(1); cdr.StatP |= STATUS_ROTATING; cdr.StatP &= ~STATUS_SEEK; cdr.Result[0] = cdr.StatP; cdr.Seeked = SEEK_DONE; if (cdr.Irq == 0) { cdr.Stat = Complete; setIrq(); } if (cdr.SetlocPending) { memcpy(cdr.SetSectorPlay, cdr.SetSector, 4); cdr.SetlocPending = 0; } Find_CurTrack(cdr.SetSectorPlay); ReadTrack(cdr.SetSectorPlay); cdr.TrackChanged = FALSE; } if (!cdr.Play) return; CDR_LOG( "CDDA - %d:%d:%d\n", cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2] ); if (memcmp(cdr.SetSectorPlay, cdr.SetSectorEnd, 3) == 0) { StopCdda(); cdr.TrackChanged = TRUE; } if (!cdr.Irq && !cdr.Stat && (cdr.Mode & (MODE_AUTOPAUSE|MODE_REPORT))) cdrPlayInterrupt_Autopause(); if (!cdr.Play) return; cdr.SetSectorPlay[2]++; if (cdr.SetSectorPlay[2] == 75) { cdr.SetSectorPlay[2] = 0; cdr.SetSectorPlay[1]++; if (cdr.SetSectorPlay[1] == 60) { cdr.SetSectorPlay[1] = 0; cdr.SetSectorPlay[0]++; } } CDRMISC_INT(cdReadTime); // update for CdlGetlocP/autopause generate_subq(cdr.SetSectorPlay); //senquack - Copy/pasted CHUI's ResetIoCycle() call into this new function // TODO: Are these really beneficial/necessary? // CHUI: Añado ResetIoCycle para permite que en el proximo salto entre en psxBranchTest ResetIoCycle(); }
INLINE void setIrq( u32 irq ) { psxHu32ref(0x1070) |= SWAPu32(irq); // CHUI: Añado ResetIoCycle para permite que en el proximo salto entre en psxBranchTest ResetIoCycle(); }
void psxRcntUpdate() { #ifdef DEBUG_ANALYSIS dbg_anacnt_psxRcntUpdate++; #endif pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_COUNTERS,PCSX4ALL_PROF_CPU); u32 cycle; cycle = psxRegs.cycle; #ifdef USE_EXTRA_IO_CYCLES // CHUI: Añado ResetIoCycle para permite que en el proximo salto entre en psxBranchTest ResetIoCycle(); #endif // rcnt 0. if( cycle - rcnts[0].cycleStart >= rcnts[0].cycle ) { psxRcntReset( 0 ); } // rcnt 1. if( cycle - rcnts[1].cycleStart >= rcnts[1].cycle ) { psxRcntReset( 1 ); } // rcnt 2. if( cycle - rcnts[2].cycleStart >= rcnts[2].cycle ) { psxRcntReset( 2 ); } // rcnt base. if( cycle - rcnts[3].cycleStart >= rcnts[3].cycle ) { psxRcntReset( 3 ); spuSyncCount++; hSyncCount++; // Update spu. if( spuSyncCount >= SPU_UPD_INTERVAL ) { spuSyncCount = 0; SPU_async(); } /* // For the best times. :D // VSync irq. if( hSyncCount == VBlankStart[Config.PsxType] ) { setIrq( 0x01 ); } */ // Update lace. (with InuYasha fix) if( hSyncCount >= (Config.VSyncWA ? UDIV(HSyncTotal[Config.PsxType],BIAS) : HSyncTotal[Config.PsxType]) ) { #ifdef DEBUG_BIOS dbg("UpdateLace"); #endif hSyncCount = 0; setIrq( 0x01 ); GPU_updateLace(); pad_update(); #ifdef DEBUG_END_FRAME { static unsigned _endframe_=0; static unsigned _frametime_[DEBUG_END_FRAME+1]; _frametime_[_endframe_]=(get_ticks() #ifndef TIME_IN_MSEC /1000 #endif ); _endframe_++; if (_endframe_>DEBUG_END_FRAME) { unsigned i; for(i=1;i<_endframe_;i++) printf("FRAME %u = %u msec\n",i,_frametime_[i]-_frametime_[i-1]); pcsx4all_exit(); } } #endif if ((toSaveState)&&(SaveState_filename)) { toSaveState=0; SaveState(SaveState_filename); if (toExit) pcsx4all_exit(); } if ((toLoadState)&&(SaveState_filename)) { toLoadState=0; LoadState(SaveState_filename); pcsx4all_prof_reset(); #ifdef PROFILER_PCSX4ALL _pcsx4all_prof_end(PCSX4ALL_PROF_CPU,0); #endif pcsx4all_prof_start(PCSX4ALL_PROF_CPU); psxCpu->Execute(); pcsx4all_prof_end(PCSX4ALL_PROF_CPU); pcsx4all_exit(); } } } pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_COUNTERS,PCSX4ALL_PROF_CPU); }