void psxRcntUpdate() { int i; //u32 change = 0; g_iopNextEventCycle = psxRegs.cycle + 32; psxNextCounter = 0x7fffffff; psxNextsCounter = psxRegs.cycle; for (i=0; i<=5; i++) { s32 change = psxRegs.cycle - psxCounters[i].sCycleT; // don't count disabled or hblank counters... // We can't check the ALTSOURCE flag because the PSXCLOCK source *should* // be counted here. if( psxCounters[i].mode & IOPCNT_STOPPED ) continue; if ((psxCounters[i].mode & 0x40) && !(psxCounters[i].mode & 0x80)) { //Repeat IRQ mode Pulsed, resets a few cycles after the interrupt, this should do. psxCounters[i].mode |= 0x400; } if( psxCounters[i].rate == PSXHBLANK ) continue; if( change <= 0 ) continue; psxCounters[i].count += change / psxCounters[i].rate; if(psxCounters[i].rate != 1) { change -= (change / psxCounters[i].rate) * psxCounters[i].rate; psxCounters[i].sCycleT = psxRegs.cycle - change; } else psxCounters[i].sCycleT = psxRegs.cycle; } // Do target/overflow testing // Optimization Note: This approach is very sound. Please do not try to unroll it // as the size of the Test functions will cause code cache clutter and slowness. for( i=0; i<6; i++ ) { // don't do target/oveflow checks for hblankers. Those // checks are done when the counters are updated. if( psxCounters[i].rate == PSXHBLANK ) continue; if( psxCounters[i].mode & IOPCNT_STOPPED ) continue; _rcntTestTarget( i ); _rcntTestOverflow( i ); // perform second target test because if we overflowed above it's possible we // already shot past our target if it was very near zero. //if( psxCounters[i].count >= psxCounters[i].target ) _rcntTestTarget( i ); } if(SPU2async) { const s32 difference = psxRegs.cycle - psxCounters[6].sCycleT; s32 c = psxCounters[6].CycleT; if(difference >= psxCounters[6].CycleT) { SPU2async(difference); psxCounters[6].sCycleT = psxRegs.cycle; psxCounters[6].CycleT = psxCounters[6].rate; } else c -= difference; psxNextCounter = c; } if (DEV9async) { DEV9async(1); } if(USBasync) { const s32 difference = psxRegs.cycle - psxCounters[7].sCycleT; s32 c = psxCounters[7].CycleT; if(difference >= psxCounters[7].CycleT) { USBasync(difference); psxCounters[7].sCycleT = psxRegs.cycle; psxCounters[7].CycleT = psxCounters[7].rate; } else c -= difference; if (c < psxNextCounter) psxNextCounter = c; } #ifdef ENABLE_NEW_IOPDMA // New Iop DMA handler WIP { const s32 difference = psxRegs.cycle - psxCounters[8].sCycleT; s32 c = psxCounters[8].CycleT; if(difference >= psxCounters[8].CycleT) { psxCounters[8].sCycleT = psxRegs.cycle; psxCounters[8].CycleT = psxCounters[8].rate; IopDmaUpdate(difference); } else c -= difference; if (c < psxNextCounter) psxNextCounter = c; } #endif for (i=0; i<6; i++) _rcntSet( i ); }
void psxRcntUpdate() { int i; //u32 change = 0; for (i=0; i<=5; i++) { s32 change = psxRegs.cycle - psxCounters[i].sCycleT; // don't count disabled, gated, or hblank counters... // We can't check the ALTSOURCE flag because the PSXCLOCK source *should* // be counted here. if( psxCounters[i].mode & (IOPCNT_STOPPED | IOPCNT_ENABLE_GATE) ) continue; if( psxCounters[i].rate == PSXHBLANK ) continue; if( change <= 0 ) continue; psxCounters[i].count += change / psxCounters[i].rate; if(psxCounters[i].rate != 1) { change -= (change / psxCounters[i].rate) * psxCounters[i].rate; psxCounters[i].sCycleT = psxRegs.cycle - change; } else psxCounters[i].sCycleT = psxRegs.cycle; } // Do target/overflow testing // Optimization Note: This approach is very sound. Please do not try to unroll it // as the size of the Test functions will cause code cache clutter and slowness. for( i=0; i<6; i++ ) { // don't do target/oveflow checks for hblankers. Those // checks are done when the counters are updated. if( psxCounters[i].rate == PSXHBLANK ) continue; if( psxCounters[i].mode & IOPCNT_STOPPED ) continue; _rcntTestTarget( i ); _rcntTestOverflow( i ); // perform second target test because if we overflowed above it's possible we // already shot past our target if it was very near zero. //if( psxCounters[i].count >= psxCounters[i].target ) _rcntTestTarget( i ); } psxNextCounter = 0xffffff; psxNextsCounter = psxRegs.cycle; if(SPU2async) { const s32 difference = psxRegs.cycle - psxCounters[6].sCycleT; s32 c = psxCounters[6].CycleT; if(difference >= psxCounters[6].CycleT) { SPU2async(difference); psxCounters[6].sCycleT = psxRegs.cycle; psxCounters[6].CycleT = psxCounters[6].rate; } else c -= difference; psxNextCounter = c; } if(USBasync) { const s32 difference = psxRegs.cycle - psxCounters[7].sCycleT; s32 c = psxCounters[7].CycleT; if(difference >= psxCounters[7].CycleT) { USBasync(difference); psxCounters[7].sCycleT = psxRegs.cycle; psxCounters[7].CycleT = psxCounters[7].rate; } else c -= difference; if (c < psxNextCounter) psxNextCounter = c; } for (i=0; i<6; i++) _rcntSet( i ); }
EXPORT_C_(void) s2r_replay(HWND hwnd, HINSTANCE hinst, LPSTR filename, int nCmdShow) { #ifndef ENABLE_NEW_IOPDMA_SPU2 int events=0; Running = true; #ifdef WIN32 AllocConsole(); SetConsoleCtrlHandler(HandlerRoutine, TRUE); conprintf("Playing %s file on %x...",filename,hwnd); #endif // load file FILE *file=fopen(filename,"rb"); if(!file) { conprintf("Could not open the replay file."); return; } // if successful, init the plugin #define TryRead(dest,size,count,file) if(fread(dest,size,count,file)<count) { conprintf("Error reading from file."); goto Finish; /* Need to exit the while() loop and maybe also the switch */ } TryRead(&CurrentIOPCycle,4,1,file); replay_mode=true; InitWaitSync(); // Initialize the WaitSync stuff SPU2init(); SPU2irqCallback(dummy1,dummy4,dummy7); SPU2setClockPtr(&CurrentIOPCycle); SPU2open(&hwnd); CurrentIOPCycle=0; SPU2async(0); while(!feof(file) && Running) { u32 ccycle=0; u32 evid=0; u32 sval=0; u32 tval=0; TryRead(&ccycle,4,1,file); TryRead(&sval,4,1,file); evid=sval>>29; sval&=0x1FFFFFFF; u32 TargetCycle = ccycle * 768; while(TargetCycle > CurrentIOPCycle) { u32 delta = WaitSync(TargetCycle); SPU2async(delta); } switch(evid) { case 0: SPU2read(sval); break; case 1: TryRead(&tval,2,1,file); SPU2write(sval,tval); break; case 2: TryRead(dmabuffer,sval,2,file); SPU2writeDMA4Mem(dmabuffer,sval); break; case 3: TryRead(dmabuffer,sval,2,file); SPU2writeDMA7Mem(dmabuffer,sval); break; default: // not implemented return; break; } events++; } Finish: //shutdown SPU2close(); SPU2shutdown(); fclose(file); conprintf("Finished playing %s file (%d cycles, %d events).",filename,CurrentIOPCycle,events); #ifdef WIN32 FreeConsole(); #endif replay_mode=false; #endif }