static void psxRcntReset( u32 index ) { u32 count; if( rcnts[index].counterState == CountToTarget ) { if( rcnts[index].mode & RcCountToTarget ) { count = psxRegs.cycle; count -= rcnts[index].cycleStart; count /= rcnts[index].rate; count -= rcnts[index].target; } else { count = _psxRcntRcount( index ); } _psxRcntWcount( index, count ); if( rcnts[index].mode & RcIrqOnTarget ) { if( (rcnts[index].mode & RcIrqRegenerate) || (!rcnts[index].irqState) ) { verboseLog( 3, "[RCNT %i] irq: %x\n", index, count ); setIrq( rcnts[index].irq ); rcnts[index].irqState = 1; } } rcnts[index].mode |= RcCountEqTarget; } else if( rcnts[index].counterState == CountToOverflow ) { count = psxRegs.cycle; count -= rcnts[index].cycleStart; count /= rcnts[index].rate; count -= 0xffff; _psxRcntWcount( index, count ); if( rcnts[index].mode & RcIrqOnOverflow ) { if( (rcnts[index].mode & RcIrqRegenerate) || (!rcnts[index].irqState) ) { verboseLog( 3, "[RCNT %i] irq: %x\n", index, count ); setIrq( rcnts[index].irq ); rcnts[index].irqState = 1; } } rcnts[index].mode |= RcOverflow; } rcnts[index].mode |= RcUnknown10; psxRcntSet(); }
// 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); }
static void cdrPlayInterrupt_Autopause() { if ((cdr.Mode & MODE_AUTOPAUSE) && cdr.TrackChanged) { CDR_LOG( "CDDA STOP\n" ); // Magic the Gathering // - looping territory cdda // ...? //cdr.ResultReady = 1; //cdr.Stat = DataReady; cdr.Stat = DataEnd; setIrq(); StopCdda(); } else if (cdr.Mode & MODE_REPORT) { cdr.Result[0] = cdr.StatP; cdr.Result[1] = cdr.subq.Track; cdr.Result[2] = cdr.subq.Index; if (cdr.subq.Absolute[2] & 0x10) { cdr.Result[3] = cdr.subq.Relative[0]; cdr.Result[4] = cdr.subq.Relative[1] | 0x80; cdr.Result[5] = cdr.subq.Relative[2]; } else { cdr.Result[3] = cdr.subq.Absolute[0]; cdr.Result[4] = cdr.subq.Absolute[1]; cdr.Result[5] = cdr.subq.Absolute[2]; } cdr.Result[6] = 0; cdr.Result[7] = 0; // Rayman: Logo freeze (resultready + dataready) cdr.ResultReady = 1; cdr.Stat = DataReady; SetResultSize(8); setIrq(); } }
void psxRcntUpdate() { u32 cycle; cycle = psxRegs.cycle; // 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 ) { u32 leftover_cycles = cycle - rcnts[3].cycleStart - rcnts[3].cycle; u32 next_vsync; hSyncCount += hsync_steps; // VSync irq. if( hSyncCount == VBlankStart ) { HW_GPU_STATUS &= ~PSXGPU_LCF; GPU_vBlank( 1, 0 ); setIrq( 0x01 ); EmuUpdate(); GPU_updateLace(); if( SPU_async ) { SPU_async( cycle, 1 ); } } // Update lace. (with InuYasha fix) if( hSyncCount >= (Config.VSyncWA ? HSyncTotal[Config.PsxType] / BIAS : HSyncTotal[Config.PsxType]) ) { hSyncCount = 0; frame_counter++; gpuSyncPluginSR(); if( (HW_GPU_STATUS & PSXGPU_ILACE_BITS) == PSXGPU_ILACE_BITS ) HW_GPU_STATUS |= frame_counter << 31; GPU_vBlank( 0, HW_GPU_STATUS >> 31 ); }
void psxRcntUpdate() { u32 cycle; cycle = psxRegs.cycle; // 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 >= SpuUpdInterval[Config.PsxType] ) { spuSyncCount = 0; if( SPU_async ) { SPU_async( SpuUpdInterval[Config.PsxType] * rcnts[3].target ); } } // VSync irq. if( hSyncCount == VBlankStart[Config.PsxType] ) { GPU_vBlank( 1 ); // For the best times. :D //setIrq( 0x01 ); } // Update lace. (with InuYasha fix) if( hSyncCount >= (Config.VSyncWA ? HSyncTotal[Config.PsxType] / BIAS : HSyncTotal[Config.PsxType]) ) { hSyncCount = 0; GPU_vBlank( 0 ); setIrq( 0x01 ); GPU_updateLace(); EmuUpdate(); } } #ifndef LIBXENON DebugVSync(); #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_NOT_READY; 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 }
void psxRcntUpdate() { u32 cycle; cycle = psxRegs.cycle; // 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 ); GPU_hSync(hSyncCount); spuSyncCount++; hSyncCount++; // Update spu. if( spuSyncCount >= SpuUpdInterval[Config.PsxType] ) { spuSyncCount = 0; if( SPU_async ) { SPU_async( SpuUpdInterval[Config.PsxType] * rcnts[3].target ); } } #ifdef ENABLE_SIO1API if( SIO1_update ) { SIO1_update( 0 ); } #endif // VSync irq. if( hSyncCount == VBlankStart[Config.PsxType] ) { GPU_vBlank( 1 ); // For the best times. :D //setIrq( 0x01 ); } // Update lace. (calculated at psxHsyncCalculate() on init/defreeze) if( hSyncCount >= HSyncTotal[Config.PsxType] ) { hSyncCount = 0; GPU_vBlank( 0 ); setIrq( 0x01 ); GPU_updateLace(); EmuUpdate(); } } DebugVSync(); }
static void psxRcntReset( u32 index ) { u32 rcycles; rcnts[index].mode |= RcUnknown10; if( rcnts[index].counterState == CountToTarget ) { rcycles = psxRegs.cycle - rcnts[index].cycleStart; if( rcnts[index].mode & RcCountToTarget ) { rcycles -= rcnts[index].target * rcnts[index].rate; rcnts[index].cycleStart = psxRegs.cycle - rcycles; } else { rcnts[index].cycle = 0x10000 * rcnts[index].rate; rcnts[index].counterState = CountToOverflow; } if( rcnts[index].mode & RcIrqOnTarget ) { if( (rcnts[index].mode & RcIrqRegenerate) || (!rcnts[index].irqState) ) { verboseLog( 3, "[RCNT %i] irq\n", index ); setIrq( rcnts[index].irq ); rcnts[index].irqState = 1; } } rcnts[index].mode |= RcCountEqTarget; if( rcycles < 0x10000 * rcnts[index].rate ) return; } if( rcnts[index].counterState == CountToOverflow ) { rcycles = psxRegs.cycle - rcnts[index].cycleStart; rcycles -= 0x10000 * rcnts[index].rate; rcnts[index].cycleStart = psxRegs.cycle - rcycles; if( rcycles < rcnts[index].target * rcnts[index].rate ) { rcnts[index].cycle = rcnts[index].target * rcnts[index].rate; rcnts[index].counterState = CountToTarget; } if( rcnts[index].mode & RcIrqOnOverflow ) { if( (rcnts[index].mode & RcIrqRegenerate) || (!rcnts[index].irqState) ) { verboseLog( 3, "[RCNT %i] irq\n", index ); setIrq( rcnts[index].irq ); rcnts[index].irqState = 1; } } rcnts[index].mode |= RcOverflow; } }
void psxHwWrite32(u32 add, u32 value) { switch (add) { case 0x1f801040: sioWrite8((unsigned char)value); sioWrite8((unsigned char)((value&0xff) >> 8)); sioWrite8((unsigned char)((value&0xff) >> 16)); sioWrite8((unsigned char)((value&0xff) >> 24)); #ifdef PAD_LOG PAD_LOG("sio write32 %x\n", value); #endif return; #ifdef ENABLE_SIO1API case 0x1f801050: SIO1_writeData32(value); #ifdef SIO1_LOG SIO1_LOG("sio1 write32 %x\n", value); #endif return; #endif #ifdef PSXHW_LOG case 0x1f801060: PSXHW_LOG("RAM size write %x\n", value); psxHu32ref(add) = SWAPu32(value); return; // Ram size #endif case 0x1f801070: #ifdef PSXHW_LOG PSXHW_LOG("IREG 32bit write %x\n", value); #endif if (Config.SioIrq) psxHu32ref(0x1070) |= SWAPu32(0x80); if (Config.SpuIrq) psxHu32ref(0x1070) |= SWAPu32(0x200); psxHu32ref(0x1070) &= SWAPu32(value); return; case 0x1f801074: #ifdef PSXHW_LOG PSXHW_LOG("IMASK 32bit write %x\n", value); #endif psxHu32ref(0x1074) = SWAPu32(value); return; #ifdef PSXHW_LOG case 0x1f801080: PSXHW_LOG("DMA0 MADR 32bit write %x\n", value); HW_DMA0_MADR = SWAPu32(value); return; // DMA0 madr case 0x1f801084: PSXHW_LOG("DMA0 BCR 32bit write %x\n", value); HW_DMA0_BCR = SWAPu32(value); return; // DMA0 bcr #endif case 0x1f801088: #ifdef PSXHW_LOG PSXHW_LOG("DMA0 CHCR 32bit write %x\n", value); #endif DmaExec(0); // DMA0 chcr (MDEC in DMA) return; #ifdef PSXHW_LOG case 0x1f801090: PSXHW_LOG("DMA1 MADR 32bit write %x\n", value); HW_DMA1_MADR = SWAPu32(value); return; // DMA1 madr case 0x1f801094: PSXHW_LOG("DMA1 BCR 32bit write %x\n", value); HW_DMA1_BCR = SWAPu32(value); return; // DMA1 bcr #endif case 0x1f801098: #ifdef PSXHW_LOG PSXHW_LOG("DMA1 CHCR 32bit write %x\n", value); #endif DmaExec(1); // DMA1 chcr (MDEC out DMA) return; #ifdef PSXHW_LOG case 0x1f8010a0: PSXHW_LOG("DMA2 MADR 32bit write %x\n", value); HW_DMA2_MADR = SWAPu32(value); return; // DMA2 madr case 0x1f8010a4: PSXHW_LOG("DMA2 BCR 32bit write %x\n", value); HW_DMA2_BCR = SWAPu32(value); return; // DMA2 bcr #endif case 0x1f8010a8: #ifdef PSXHW_LOG PSXHW_LOG("DMA2 CHCR 32bit write %x\n", value); #endif /* A hack that makes Vampire Hunter D title screen visible, /* but makes Tomb Raider II water effect to stay opaque /* Root cause for this problem is that when DMA2 is issued /* it is incompletele and still beign built by the game. /* Maybe it is ready when some signal comes in or within given delay? */ if (dmaGpuListHackEn && value == 0x00000401 && HW_DMA2_BCR == 0x0) { psxDma2(SWAPu32(HW_DMA2_MADR), SWAPu32(HW_DMA2_BCR), SWAPu32(value)); return; } DmaExec(2); // DMA2 chcr (GPU DMA) if (HW_DMA2_CHCR == 0x1000401) dmaGpuListHackEn=TRUE; return; #ifdef PSXHW_LOG case 0x1f8010b0: PSXHW_LOG("DMA3 MADR 32bit write %x\n", value); HW_DMA3_MADR = SWAPu32(value); return; // DMA3 madr case 0x1f8010b4: PSXHW_LOG("DMA3 BCR 32bit write %x\n", value); HW_DMA3_BCR = SWAPu32(value); return; // DMA3 bcr #endif case 0x1f8010b8: #ifdef PSXHW_LOG PSXHW_LOG("DMA3 CHCR 32bit write %x\n", value); #endif DmaExec(3); // DMA3 chcr (CDROM DMA) return; #ifdef PSXHW_LOG case 0x1f8010c0: PSXHW_LOG("DMA4 MADR 32bit write %x\n", value); HW_DMA4_MADR = SWAPu32(value); return; // DMA4 madr case 0x1f8010c4: PSXHW_LOG("DMA4 BCR 32bit write %x\n", value); HW_DMA4_BCR = SWAPu32(value); return; // DMA4 bcr #endif case 0x1f8010c8: #ifdef PSXHW_LOG PSXHW_LOG("DMA4 CHCR 32bit write %x\n", value); #endif DmaExec(4); // DMA4 chcr (SPU DMA) return; #if 0 case 0x1f8010d0: break; //DMA5write_madr(); case 0x1f8010d4: break; //DMA5write_bcr(); case 0x1f8010d8: break; //DMA5write_chcr(); // Not needed #endif #ifdef PSXHW_LOG case 0x1f8010e0: PSXHW_LOG("DMA6 MADR 32bit write %x\n", value); HW_DMA6_MADR = SWAPu32(value); return; // DMA6 bcr case 0x1f8010e4: PSXHW_LOG("DMA6 BCR 32bit write %x\n", value); HW_DMA6_BCR = SWAPu32(value); return; // DMA6 bcr #endif case 0x1f8010e8: #ifdef PSXHW_LOG PSXHW_LOG("DMA6 CHCR 32bit write %x\n", value); #endif DmaExec(6); // DMA6 chcr (OT clear) return; #ifdef PSXHW_LOG case 0x1f8010f0: PSXHW_LOG("DMA PCR 32bit write %x\n", value); HW_DMA_PCR = SWAPu32(value); return; #endif case 0x1f8010f4: #ifdef PSXHW_LOG PSXHW_LOG("DMA ICR 32bit write %x\n", value); #endif { u32 tmp = (~value) & SWAPu32(HW_DMA_ICR); HW_DMA_ICR = SWAPu32(((tmp ^ value) & 0xffffff) ^ tmp); return; } case 0x1f801014: #ifdef PSXHW_LOG PSXHW_LOG("SPU delay [0x1014] write32: %8.8lx\n", value); #endif psxHu32ref(add) = SWAPu32(value); return; case 0x1f801810: #ifdef PSXHW_LOG PSXHW_LOG("GPU DATA 32bit write %x (CMD/MSB %x)\n", value, value>>24); #endif // 0x1F means irq request, so fulfill it here because plugin can't and won't // Probably no need to send this to plugin in first place... // MML/Tronbonne is known to use this. // TODO FIFO is not implemented properly so commands are not exact // and thus we rely on hack that counter/cdrom irqs are enabled at same time if (SWAPu32(value) == 0x1f00000 && (psxHu32ref(0x1070) & 0x44)) { setIrq( 0x01 ); } GPU_writeData(value); return; case 0x1f801814: #ifdef PSXHW_LOG PSXHW_LOG("GPU STATUS 32bit write %x\n", value); #endif if (value & 0x8000000) dmaGpuListHackEn=FALSE; GPU_writeStatus(value); return; case 0x1f801820: mdecWrite0(value); break; case 0x1f801824: mdecWrite1(value); break; case 0x1f801100: #ifdef PSXHW_LOG PSXHW_LOG("COUNTER 0 COUNT 32bit write %x\n", value); #endif psxRcntWcount(0, value & 0xffff); return; case 0x1f801104: #ifdef PSXHW_LOG PSXHW_LOG("COUNTER 0 MODE 32bit write %x\n", value); #endif psxRcntWmode(0, value); return; case 0x1f801108: #ifdef PSXHW_LOG PSXHW_LOG("COUNTER 0 TARGET 32bit write %x\n", value); #endif psxRcntWtarget(0, value & 0xffff); return; // HW_DMA_ICR&= SWAP32((~value)&0xff000000); case 0x1f801110: #ifdef PSXHW_LOG PSXHW_LOG("COUNTER 1 COUNT 32bit write %x\n", value); #endif psxRcntWcount(1, value & 0xffff); return; case 0x1f801114: #ifdef PSXHW_LOG PSXHW_LOG("COUNTER 1 MODE 32bit write %x\n", value); #endif psxRcntWmode(1, value); return; case 0x1f801118: #ifdef PSXHW_LOG PSXHW_LOG("COUNTER 1 TARGET 32bit write %x\n", value); #endif psxRcntWtarget(1, value & 0xffff); return; case 0x1f801120: #ifdef PSXHW_LOG PSXHW_LOG("COUNTER 2 COUNT 32bit write %x\n", value); #endif psxRcntWcount(2, value & 0xffff); return; case 0x1f801124: #ifdef PSXHW_LOG PSXHW_LOG("COUNTER 2 MODE 32bit write %x\n", value); #endif psxRcntWmode(2, value); return; case 0x1f801128: #ifdef PSXHW_LOG PSXHW_LOG("COUNTER 2 TARGET 32bit write %x\n", value); #endif psxRcntWtarget(2, value & 0xffff); return; default: // Dukes of Hazard 2 - car engine noise if (add>=0x1f801c00 && add<0x1f801e00) { SPU_writeRegister(add, value&0xffff); add += 2; value >>= 16; if (add>=0x1f801c00 && add<0x1f801e00) SPU_writeRegister(add, value&0xffff); return; } psxHu32ref(add) = SWAPu32(value); #ifdef PSXHW_LOG PSXHW_LOG("*Unknown 32bit write at address %x value %x\n", add, value); #endif return; }
// 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(); }
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); }
static void psxRcntReset( u32 index ) { u32 count; if( rcnts[index].counterState == CountToTarget ) { if( rcnts[index].mode & RcCountToTarget ) { count = psxRegs.cycle; count -= rcnts[index].cycleStart; if (rcnts[index].rate > 1) count = UDIV(count,rcnts[index].rate); count -= rcnts[index].target; } else { count = _psxRcntRcount( index ); } _psxRcntWcount( index, count ); if( rcnts[index].mode & RcIrqOnTarget ) { if( (rcnts[index].mode & RcIrqRegenerate) || (!rcnts[index].irqState) ) { #ifdef DEBUG_BIOS dbgf("[RCNT %i] irq: %x\n", index, count ); #endif setIrq( rcnts[index].irq ); rcnts[index].irqState = 1; } } rcnts[index].mode |= RcCountEqTarget; } else if( rcnts[index].counterState == CountToOverflow ) { count = psxRegs.cycle; count -= rcnts[index].cycleStart; if (rcnts[index].rate > 1) count = UDIV(count,rcnts[index].rate); count -= 0xffff; _psxRcntWcount( index, count ); if( rcnts[index].mode & RcIrqOnOverflow ) { if( (rcnts[index].mode & RcIrqRegenerate) || (!rcnts[index].irqState) ) { #ifdef DEBUG_BIOS dbgf("[RCNT %i] irq: %x\n", index, count ); #endif setIrq( rcnts[index].irq ); rcnts[index].irqState = 1; } } rcnts[index].mode |= RcOverflow; } rcnts[index].mode |= RcUnknown10; psxRcntSet(); }