diff --git a/pcsx2/Counters.c b/pcsx2/Counters.c index 28fb0f0953..3f000f2397 100644 --- a/pcsx2/Counters.c +++ b/pcsx2/Counters.c @@ -75,7 +75,16 @@ static __forceinline void _rcntSet( int i ) static __forceinline void cpuRcntSet() { int i; - nextCounter = (counters[4].CycleT < counters[5].CycleT) ? counters[4].CycleT : counters[5].CycleT; + // Calculate our target cycle deltas. + // This must be done regardless of if the hblank/vblank counters updated since + // cpuRegs.cycle changes, even if sCycle hasn't! + + u32 counter4CycleT = ( counters[4].mode == MODE_HBLANK ) ? HBLANK_TIME_ : HRENDER_TIME_; + u32 counter5CycleT = VSYNC_HALF_ - (cpuRegs.cycle - counters[5].sCycle); + counter4CycleT -= (cpuRegs.cycle - counters[4].sCycle); + + nextCounter = (counter4CycleT < counter5CycleT) ? counter4CycleT : counter5CycleT; + nextsCounter = cpuRegs.cycle; for (i = 0; i < 4; i++) @@ -384,24 +393,38 @@ static __forceinline void VSyncEnd(u32 sCycle) // VSync End frameLimit(); // limit FPS (also handles frameskip and VUskip) } -#define hScanlineNextCycle(diff, cyclesAmount) { \ - u32 compareValue = (SCANLINE_ + cyclesAmount); \ - if (diff >= compareValue) { \ - u32 increment = (diff / compareValue); \ - /*SysPrintf("Counters Optimization\n");*/ \ - /* if counter's count increases on hblank gate's off signal OR if counter increases every hblank, THEN add to the counter */ \ - if ( (!(counters[0].mode & 0x30) && (gates & (1<<0))) || (((counters[0].mode & 0x83) == 0x83) && !(gates & (1<<0))) ) counters[0].count += (increment * HBLANK_COUNTER_SPEED); \ - if ( (!(counters[1].mode & 0x30) && (gates & (1<<1))) || (((counters[1].mode & 0x83) == 0x83) && !(gates & (1<<1))) ) counters[1].count += (increment * HBLANK_COUNTER_SPEED); \ - if ( (!(counters[2].mode & 0x30) && (gates & (1<<2))) || (((counters[2].mode & 0x83) == 0x83) && !(gates & (1<<2))) ) counters[2].count += (increment * HBLANK_COUNTER_SPEED); \ - if ( (!(counters[3].mode & 0x30) && (gates & (1<<3))) || (((counters[3].mode & 0x83) == 0x83) && !(gates & (1<<3))) ) counters[3].count += (increment * HBLANK_COUNTER_SPEED); \ - counters[4].sCycle += (increment * compareValue); \ - } \ - else counters[4].sCycle += cyclesAmount; \ - counters[4].CycleT = (s32)(cyclesAmount - (cpuRegs.cycle - counters[4].sCycle)); \ - if ((s32)counters[4].CycleT < 0) { \ - counters[4].sCycle += (((s32)counters[4].CycleT) * -1); \ - counters[4].CycleT = 0; \ - } \ +static __forceinline void hScanlineNextCycle( u32 diff, u32 cyclesAmount ) +{ + // This function: Now Unneeded? + // This code doesn't appear to be run anymore after fixing the CycleT bug + // and fixing the EE/IOP code execution sync issues (tested on 6 games, + // with EEx3 hack too). + + // And it makes sense -- bad behavior by the counters would have led + // to cpuBranchTest being delayed beyond the span of a full hsync. + // It could still happen in some isolated part of some particular game, + // but probably we're better off letting that game lose a couple hsyncs + // once in a while rather than slow everyone else down needlessly. + + u32 scanlineCycles = SCANLINE_; + diff -= cyclesAmount; + if (diff >= scanlineCycles) + { + u32 increment = diff / scanlineCycles; + + // Counter Optimization: + // If the time passed is beyond a single scanline, then increment all scanline + // counters as a set here. + + SysPrintf("Counters Optimization %d\n", diff / scanlineCycles); + + /* if counter's count increases on hblank gate's off signal OR if counter increases every hblank, THEN add to the counter */ + if ( (!(counters[0].mode & 0x30) && (gates & (1<<0))) || (((counters[0].mode & 0x83) == 0x83) && !(gates & (1<<0))) ) counters[0].count += (increment * HBLANK_COUNTER_SPEED); + if ( (!(counters[1].mode & 0x30) && (gates & (1<<1))) || (((counters[1].mode & 0x83) == 0x83) && !(gates & (1<<1))) ) counters[1].count += (increment * HBLANK_COUNTER_SPEED); + if ( (!(counters[2].mode & 0x30) && (gates & (1<<2))) || (((counters[2].mode & 0x83) == 0x83) && !(gates & (1<<2))) ) counters[2].count += (increment * HBLANK_COUNTER_SPEED); + if ( (!(counters[3].mode & 0x30) && (gates & (1<<3))) || (((counters[3].mode & 0x83) == 0x83) && !(gates & (1<<3))) ) counters[3].count += (increment * HBLANK_COUNTER_SPEED); + counters[4].sCycle += (increment * scanlineCycles); + } } static __forceinline void hScanline() @@ -409,16 +432,20 @@ static __forceinline void hScanline() u32 difference = (cpuRegs.cycle - counters[4].sCycle); if (counters[4].mode & MODE_HBLANK) { //HBLANK Start - if (difference >= HBLANK_TIME_ ) { - hScanlineNextCycle(difference, HBLANK_TIME_); + const u32 modeCycles = HBLANK_TIME_; + if (difference >= modeCycles ) { + //hScanlineNextCycle(difference, modeCycles); + counters[4].sCycle += modeCycles; rcntStartGate(0, counters[4].sCycle); psxCheckStartGate16(0); counters[4].mode = MODE_HRENDER; } } else { //HBLANK END / HRENDER Begin - if (difference >= (HRENDER_TIME_)) { - hScanlineNextCycle(difference, HRENDER_TIME_); + const u32 modeCycles = HRENDER_TIME_; + if (difference >= modeCycles) { + //hScanlineNextCycle(difference, modeCycles); + counters[4].sCycle += modeCycles; if (CSRw & 0x4) GSCSRr |= 4; // signal if (!(GSIMR&0x400)) gsIrq(); if (gates) rcntEndGate(0, counters[4].sCycle); @@ -426,18 +453,23 @@ static __forceinline void hScanline() counters[4].mode = MODE_HBLANK; } } + + /*if(counters[4].CycleT < 0) { + counters[4].sCycle += -counters[4].CycleT; + counters[4].CycleT = 0; + }*/ + } // Only called from one place so might as well inline it. -static __forceinline void vSync() +static __forceinline void vSync() { u32 diff = (cpuRegs.cycle - counters[5].sCycle); hScanline(); if (diff >= (VSYNC_HALF_)) { - counters[5].sCycle += (VSYNC_HALF_ * (u32)(diff / VSYNC_HALF_)); - counters[5].CycleT = VSYNC_HALF_ - (cpuRegs.cycle - counters[5].sCycle); + counters[5].sCycle += VSYNC_HALF_; // * (u32)(diff / VSYNC_HALF_)); if (counters[5].mode == MODE_VSYNC) { VSyncEnd(counters[5].sCycle); @@ -446,7 +478,16 @@ static __forceinline void vSync() else { VSyncStart(counters[5].sCycle); counters[5].mode = MODE_VSYNC; + + // Accumulate hsync rounding errors: + counters[4].sCycle += HSYNC_ERROR; + + // Tighten up EE/IOP responsiveness for a wee bit. + // Games are usually most sensitive to vSync sessions since that's + // when the hard thinking usually occurs. + g_eeTightenSync += 2; } + g_nextBranchCycle = cpuRegs.cycle + 384; } } @@ -680,6 +721,16 @@ int rcntFreeze(gzFile f, int Mode) { gzfreeze(&nextCounter, sizeof(nextCounter)); gzfreeze(&nextsCounter, sizeof(nextsCounter)); + if( Mode == 0 ) + { + // Sanity check for loading older savestates: + if( counters[4].sCycle == 0 ) + counters[4].sCycle = cpuRegs.cycle; + + if( counters[5].sCycle == 0 ) + counters[5].sCycle = cpuRegs.cycle; + } + return 0; } diff --git a/pcsx2/Counters.h b/pcsx2/Counters.h index 2c928b8bb9..23ecd5a8ff 100644 --- a/pcsx2/Counters.h +++ b/pcsx2/Counters.h @@ -47,6 +47,8 @@ typedef struct { #define SCANLINES_VBLANK1_NTSC 19 // scanlines used for vblank1 (even interlace) #define SCANLINES_VBLANK2_NTSC 20 // scanlines used for vblank2 (odd interlace) +#define HSYNC_ERROR_NTSC ((s32)VSYNC_NTSC - (s32)(((HRENDER_TIME_NTSC+HBLANK_TIME_NTSC) * SCANLINES_TOTAL_NTSC)/2) ) + //------------------------------------------------------------------ // PAL Timing Information!!! (some scanline info is guessed) //------------------------------------------------------------------ @@ -62,6 +64,8 @@ typedef struct { #define SCANLINES_VBLANK1_PAL 19 // scanlines used for vblank1 (even interlace) #define SCANLINES_VBLANK2_PAL 20 // scanlines used for vblank2 (odd interlace) +#define HSYNC_ERROR_PAL ((s32)VSYNC_PAL - (s32)((SCANLINE_PAL * SCANLINES_TOTAL_PAL) / 2)) + //------------------------------------------------------------------ // Timing (PAL/NTSC) Information!!! //------------------------------------------------------------------ @@ -71,6 +75,8 @@ typedef struct { #define VSYNC_ ((Config.PsxType&1) ? VSYNC_PAL : VSYNC_NTSC) #define VSYNC_HALF_ ((Config.PsxType&1) ? VSYNC_HALF_PAL : VSYNC_HALF_NTSC) +#define HSYNC_ERROR ((Config.PsxType&1) ? HSYNC_ERROR_PAL : HSYNC_ERROR_NTSC) + #define SCANLINES_TOTAL_ ((Config.PsxType&1) ? SCANLINES_TOTAL_PAL : SCANLINES_TOTAL_NTSC) #define SCANLINES_VSYNC_ ((Config.PsxType&1) ? SCANLINES_VSYNC_PAL : SCANLINES_VSYNC_NTSC) #define SCANLINES_VRENDER_ ((Config.PsxType&1) ? SCANLINES_VRENDER_PAL : SCANLINES_VRENDER_NTSC) diff --git a/pcsx2/GS.cpp b/pcsx2/GS.cpp index db37d9cd02..6193b72f99 100644 --- a/pcsx2/GS.cpp +++ b/pcsx2/GS.cpp @@ -1054,7 +1054,7 @@ void GIFdma() SysPrintf("GS Stall Control Source = %x, Drain = %x\n MADR = %x, STADR = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3, gif->madr, psHu32(DMAC_STADR)); if( gif->madr + (gif->qwc * 16) > psHu32(DMAC_STADR) ) { - INT(2, gscycles); + CPU_INT(2, gscycles); gscycles = 0; return; } @@ -1165,7 +1165,7 @@ void GIFdma() prevcycles = gscycles; gif->tadr -= 16; hwDmacIrq(13); - INT(2, gscycles); + CPU_INT(2, gscycles); gscycles = 0; return; } @@ -1187,14 +1187,14 @@ void GIFdma() prevtag = NULL; prevcycles = 0; if (!(vif1Regs->mskpath3 || (psHu32(GIF_MODE) & 0x1))) { - INT(2, gscycles); + CPU_INT(2, gscycles); gscycles = 0; } } void dmaGIF() { //if(vif1Regs->mskpath3 || (psHu32(GIF_MODE) & 0x1)){ - // INT(2, 48); //Wait time for the buffer to fill, fixes some timing problems in path 3 masking + // CPU_INT(2, 48); //Wait time for the buffer to fill, fixes some timing problems in path 3 masking //} //It takes the time of 24 QW for the BUS to become ready - The Punisher, And1 Streetball //else gspath3done = 0; // For some reason this doesnt clear? So when the system starts the thread, we will clear it :) @@ -1373,7 +1373,7 @@ void mfifoGIFtransfer(int qwc) { if(gif->qwc == 0 && gifdone == 2) gifdone = 1; - INT(11,mfifocycles); + CPU_INT(11,mfifocycles); #ifdef SPR_LOG SPR_LOG("mfifoGIFtransfer end %x madr %x, tadr %x\n", gif->chcr, gif->madr, gif->tadr); @@ -1599,7 +1599,7 @@ void* GSThreadProc(void* lpParam) vif1ch->madr += vif1ch->qwc * 16; if(vif1Regs->mskpath3 == 0)vif1Regs->stat&= ~0x1f000000; - INT(1, 0); // since gs thread always lags real thread + CPU_INT(1, 0); // since gs thread always lags real thread vif1ch->qwc = 0; InterlockedExchangeAdd((long*)&g_pGSRingPos, 16); diff --git a/pcsx2/Hw.h b/pcsx2/Hw.h index 25e8db51a9..1c4b115435 100644 --- a/pcsx2/Hw.h +++ b/pcsx2/Hw.h @@ -39,13 +39,7 @@ extern u64 *psHD; #define psHu64(mem) (*(u64*)&PS2MEM_HW[(mem) & 0xffff]) extern u32 g_nextBranchCycle; - -#define INT(n, ecycle) { \ - g_nextBranchCycle = min(g_nextBranchCycle, cpuRegs.cycle+ecycle); \ - cpuRegs.interrupt|= 1 << n; \ - cpuRegs.sCycle[n] = cpuRegs.cycle; \ - cpuRegs.eCycle[n] = ecycle; \ -} +extern void CPU_INT( u32 n, u32 ecycle ); // VIF0 -- 0x10004000 -- psH[0x4000] // VIF1 -- 0x10005000 -- psH[0x5000] diff --git a/pcsx2/IPU/IPU.c b/pcsx2/IPU/IPU.c index 8d49752039..252cbd5058 100644 --- a/pcsx2/IPU/IPU.c +++ b/pcsx2/IPU/IPU.c @@ -1032,7 +1032,7 @@ void IPUCMD_WRITE(u32 val) { g_nCmdIndex = 0; if( ipuCSC(ipuRegs->cmd.DATA) ) { - if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) INT(DMAC_FROM_IPU,0); + if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) CPU_INT(DMAC_FROM_IPU,0); return; } @@ -1051,7 +1051,7 @@ void IPUCMD_WRITE(u32 val) { case SCE_IPU_IDEC: if( ipuIDEC(val) ) { // idec done, ipu0 done too - if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) INT(DMAC_FROM_IPU,0); + if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) CPU_INT(DMAC_FROM_IPU,0); return; } @@ -1064,7 +1064,7 @@ void IPUCMD_WRITE(u32 val) { case SCE_IPU_BDEC: if( ipuBDEC(val)) { - if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) INT(DMAC_FROM_IPU,0); + if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) CPU_INT(DMAC_FROM_IPU,0); if (ipuRegs->ctrl.SCD || ipuRegs->ctrl.ECD) hwIntcIrq(INTC_IPU); @@ -1136,7 +1136,7 @@ void IPUWorker() return; } - if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) INT(DMAC_FROM_IPU,0); + if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) CPU_INT(DMAC_FROM_IPU,0); break; case SCE_IPU_PACK: if( !ipuPACK(ipuRegs->cmd.DATA) ) @@ -1161,7 +1161,7 @@ void IPUWorker() ipuCurCmd = 0xffffffff; // CHECK!: IPU0dma remains when IDEC is done, so we need to clear it if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) - INT(DMAC_FROM_IPU,0); + CPU_INT(DMAC_FROM_IPU,0); s_routine = NULL; break; @@ -1177,7 +1177,7 @@ void IPUWorker() ipuRegs->topbusy = 0; ipuRegs->cmd.BUSY = 0; ipuCurCmd = 0xffffffff; - if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) INT(DMAC_FROM_IPU,0); + if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) CPU_INT(DMAC_FROM_IPU,0); s_routine = NULL; if (ipuRegs->ctrl.SCD || ipuRegs->ctrl.ECD) hwIntcIrq(INTC_IPU); @@ -1642,7 +1642,7 @@ int IPU1dma() if ((ipu1dma->chcr & 0x80) && (g_nDMATransfer&IPU_DMA_DOTIE1)) { //Check TIE bit of CHCR and IRQ bit of tag SysPrintf("IPU1 TIE\n"); - INT(DMAC_TO_IPU, totalqwc*BIAS); + CPU_INT(DMAC_TO_IPU, totalqwc*BIAS); g_nDMATransfer &= ~(IPU_DMA_ACTV1|IPU_DMA_DOTIE1); g_nDMATransfer |= IPU_DMA_TIE1; return totalqwc; @@ -1651,7 +1651,7 @@ int IPU1dma() g_nDMATransfer &= ~(IPU_DMA_ACTV1|IPU_DMA_DOTIE1); if( (ipu1dma->chcr&0xc) == 0 ) { - INT(DMAC_TO_IPU, totalqwc*BIAS); + CPU_INT(DMAC_TO_IPU, totalqwc*BIAS); return totalqwc; } else { @@ -1667,7 +1667,7 @@ int IPU1dma() ipu1dma->chcr = (ipu1dma->chcr & 0xFFFF) | ( (*ptag) & 0xFFFF0000 ); IPU_LOG("IPU dmaIrq Set\n"); - INT(DMAC_TO_IPU, totalqwc*BIAS); + CPU_INT(DMAC_TO_IPU, totalqwc*BIAS); g_nDMATransfer |= IPU_DMA_TIE1; return totalqwc; } @@ -1676,12 +1676,12 @@ int IPU1dma() { case 0x00000000: ipu1dma->tadr += 16; - INT(DMAC_TO_IPU, (1+totalqwc)*BIAS); + CPU_INT(DMAC_TO_IPU, (1+totalqwc)*BIAS); return totalqwc; case 0x70000000: ipu1dma->tadr = ipu1dma->madr; - INT(DMAC_TO_IPU, (1+totalqwc)*BIAS); + CPU_INT(DMAC_TO_IPU, (1+totalqwc)*BIAS); return totalqwc; } } @@ -1698,7 +1698,7 @@ int IPU1dma() IPU_LOG("dmaIPU1 Normal size=%d, addr=%lx, fifosize=%x\n", ipu1dma->qwc, ipu1dma->madr, 8 - g_BP.IFC); IPU1chain(); - INT(DMAC_TO_IPU, (ipu1cycles+totalqwc)*BIAS); + CPU_INT(DMAC_TO_IPU, (ipu1cycles+totalqwc)*BIAS); return totalqwc; } else @@ -1780,7 +1780,7 @@ int IPU1dma() ipu1dma->chcr = (ipu1dma->chcr & 0xFFFF) | ( (*ptag) & 0xFFFF0000 ); } - INT(DMAC_TO_IPU, ipu1cycles+totalqwc*BIAS); + CPU_INT(DMAC_TO_IPU, ipu1cycles+totalqwc*BIAS); g_nDMATransfer |= IPU_DMA_TIE1; return totalqwc; } @@ -1791,18 +1791,18 @@ int IPU1dma() { case 0x00000000: ipu1dma->tadr += 16; - INT(DMAC_TO_IPU, (ipu1cycles+totalqwc)*BIAS); + CPU_INT(DMAC_TO_IPU, (ipu1cycles+totalqwc)*BIAS); return totalqwc; case 0x70000000: ipu1dma->tadr = ipu1dma->madr; - INT(DMAC_TO_IPU, (ipu1cycles+totalqwc)*BIAS); + CPU_INT(DMAC_TO_IPU, (ipu1cycles+totalqwc)*BIAS); return totalqwc; } } } - INT(DMAC_TO_IPU, (ipu1cycles+totalqwc)*BIAS); + CPU_INT(DMAC_TO_IPU, (ipu1cycles+totalqwc)*BIAS); return totalqwc; } @@ -1912,7 +1912,7 @@ int IPU0dma() break; } } - INT(DMAC_FROM_IPU,readsize*BIAS); + CPU_INT(DMAC_FROM_IPU,readsize*BIAS); } diff --git a/pcsx2/Misc.c b/pcsx2/Misc.c index a35172029b..91614a6ff0 100644 --- a/pcsx2/Misc.c +++ b/pcsx2/Misc.c @@ -405,6 +405,7 @@ void __Log(const char *fmt, ...) { SysPrintf(tmp); } else if( emuLog != NULL ) { vfprintf(emuLog, fmt, list); + fflush( emuLog ); } #else //i assume that this will not be used (Florin) vsprintf(tmp, fmt, list); diff --git a/pcsx2/PsxCounters.c b/pcsx2/PsxCounters.c index 7192593c4f..9f189d8f81 100644 --- a/pcsx2/PsxCounters.c +++ b/pcsx2/PsxCounters.c @@ -294,9 +294,7 @@ void psxCheckStartGate32(int i) void _testRcnt16target(int i) { -#ifdef PSXCNT_LOG PSXCNT_LOG("[%d] target %x >= %x (CycleT); count=%I64x, target=%I64x, mode=%I64x\n", i, (psxRegs.cycle - psxCounters[i].sCycleT), psxCounters[i].CycleT, psxCounters[i].count, psxCounters[i].target, psxCounters[i].mode); -#endif if(psxCounters[i].target > 0xffff) { psxCounters[i].target &= 0xffff; @@ -327,10 +325,7 @@ void _testRcnt16target(int i) { void _testRcnt16overflow(int i) { -#ifdef PSXCNT_LOG - PSXCNT_LOG("[%d] overflow 0x%x >= 0x%x (Cycle); Rcount=0x%x, count=0x%x\n", i, (psxRegs.cycle - psxCounters[i].sCycle) / psxCounters[i].rate, psxCounters[i].Cycle, psxRcntRcount16(i), psxCounters[i].count); -#endif - + PSXCNT_LOG("[%d] overflow 0x%x >= 0x%x (Cycle); Rcount=0x%x, count=0x%x\n", i, (psxRegs.cycle - psxCounters[i].sCycle) / psxCounters[i].rate, psxCounters[i].Cycle, psxRcntRcount16(i), psxCounters[i].count); if (psxCounters[i].mode & 0x0020) { // Overflow interrupt psxHu32(0x1070)|= psxCounters[i].interrupt; @@ -352,9 +347,7 @@ void _testRcnt16overflow(int i) { void _testRcnt32target(int i) { -#ifdef PSXCNT_LOG PSXCNT_LOG("[%d] target %x >= %x (CycleT); count=%I64x, target=%I64x, mode=%I64x\n", i, (psxRegs.cycle - psxCounters[i].sCycleT), psxCounters[i].CycleT, psxCounters[i].count, psxCounters[i].target, psxCounters[i].mode); -#endif if(psxCounters[i].target > 0xffffffff) { //SysPrintf("IOP 32 Correcting target on target reset\n"); psxCounters[i].target &= 0xffffffff; @@ -388,9 +381,7 @@ void _testRcnt32target(int i) { void _testRcnt32overflow(int i) { -#ifdef PSXCNT_LOG PSXCNT_LOG("[%d] overflow 0x%x >= 0x%x (Cycle); Rcount=0x%x, count=0x%x\n", i, (psxRegs.cycle - psxCounters[i].sCycle), psxCounters[i].Cycle, psxRcntRcount32(i), psxCounters[i].count); -#endif //SysPrintf("Overflow 32\n"); if (psxCounters[i].mode & 0x0020) { // Overflow interrupt psxHu32(0x1070)|= psxCounters[i].interrupt; @@ -401,11 +392,13 @@ void _testRcnt32overflow(int i) { } } psxCounters[i].count -= 0x100000000ULL; - if(psxCounters[i].target > 0xffffffff) { + if(psxCounters[i].target > 0xffffffff) + { //SysPrintf("IOP 32 Correcting target on overflow\n"); - if((psxCounters[i].mode & 0x50) <= 0x40 && (psxCounters[i].mode & 0x50) != 0) SysPrintf("Counter %x overflowing, no repeat interrupt mode = %x\n", i, psxCounters[i].mode); + if((psxCounters[i].mode & 0x50) <= 0x40 && (psxCounters[i].mode & 0x50) != 0) + SysPrintf("Counter %x overflowing, no repeat interrupt mode = %x\n", i, psxCounters[i].mode); psxCounters[i].target &= 0xffffffff; - } + } } @@ -479,9 +472,7 @@ void psxRcntUpdate() { void psxRcntWcount16(int index, u32 value) { u32 change = 0; -#ifdef PSXCNT_LOG PSXCNT_LOG("writeCcount[%d] = %x\n", index, value); -#endif change = psxRegs.cycle - psxCounters[index].sCycleT; //psxCounters[i].count += change / psxCounters[i].rate; @@ -524,9 +515,7 @@ void psxRcntWcount32(int index, u32 value) { } void psxRcnt0Wmode(u32 value) { -#ifdef PSXCNT_LOG PSXCNT_LOG("IOP writeCmode[0] = %lx\n", value); -#endif #if 0 if (value & 0x1c00) { @@ -561,9 +550,7 @@ void psxRcnt0Wmode(u32 value) { } void psxRcnt1Wmode(u32 value) { -#ifdef PSXCNT_LOG PSXCNT_LOG("IOP writeCmode[1] = %lx\n", value); -#endif if (value & 0x1c00) { SysPrintf("Counter 1 Value write %x\n", value & 0x1c00); @@ -596,9 +583,7 @@ void psxRcnt1Wmode(u32 value) { } void psxRcnt2Wmode(u32 value) { -#ifdef PSXCNT_LOG PSXCNT_LOG("IOP writeCmode[2] = %lx\n", value); -#endif if (value & 0x1c00) { SysPrintf("Counter 2 Value write %x\n", value & 0x1c00); @@ -633,9 +618,7 @@ void psxRcnt2Wmode(u32 value) { } void psxRcnt3Wmode(u32 value) { -#ifdef PSXCNT_LOG PSXCNT_LOG("IOP writeCmode[3] = %lx\n", value); -#endif if (value & 0x1c00) { SysPrintf("Counter 3 Value write %x\n", value & 0x1c00); @@ -668,9 +651,7 @@ void psxRcnt3Wmode(u32 value) { } void psxRcnt4Wmode(u32 value) { -#ifdef PSXCNT_LOG PSXCNT_LOG("IOP writeCmode[4] = %lx\n", value); -#endif if (value & 0x1c00) { SysPrintf("Counter 4 Value write %x\n", value & 0x1c00); @@ -712,9 +693,7 @@ void psxRcnt4Wmode(u32 value) { } void psxRcnt5Wmode(u32 value) { -#ifdef PSXCNT_LOG PSXCNT_LOG("IOP writeCmode[5] = %lx\n", value); -#endif if (value & 0x1c00) { SysPrintf("Counter 5 Value write %x\n", value & 0x1c00); @@ -756,9 +735,7 @@ void psxRcnt5Wmode(u32 value) { } void psxRcntWtarget16(int index, u32 value) { -#ifdef PSXCNT_LOG PSXCNT_LOG("writeCtarget16[%ld] = %lx\n", index, value); -#endif psxCounters[index].target = value & 0xffff; if(psxCounters[index].target <= psxRcntCycles(index)/* && psxCounters[index].target != 0*/) { //SysPrintf("IOP 16 Saving %x target from early trigger target = %x, count = %I64x\n", index, psxCounters[index].target, psxRcntCycles(index)); @@ -769,10 +746,8 @@ void psxRcntWtarget16(int index, u32 value) { } void psxRcntWtarget32(int index, u32 value) { -#ifdef PSXCNT_LOG - PSXCNT_LOG("writeCtarget32[%ld] = %lx (count=%lx) ; sCycleT: %x CycleT: %x psxRegscycle %x\n", - index, value, psxCounters[index].count, psxCounters[index].sCycleT, psxCounters[index].CycleT, psxRegs.cycle); -#endif + PSXCNT_LOG("writeCtarget32[%ld] = %lx (count=%lx) ; sCycleT: %x CycleT: %x psxRegscycle %x\n", + index, value, psxCounters[index].count, psxCounters[index].sCycleT, psxCounters[index].CycleT, psxRegs.cycle); psxCounters[index].target = value; if(psxCounters[index].target <= psxRcntCycles(index)/* && psxCounters[index].target != 0*/) { diff --git a/pcsx2/PsxHw.h b/pcsx2/PsxHw.h index 1878073bff..92ddf83113 100644 --- a/pcsx2/PsxHw.h +++ b/pcsx2/PsxHw.h @@ -78,12 +78,7 @@ #define HW_DMA_PCR2 (psxHu32(0x1570)) #define HW_DMA_ICR2 (psxHu32(0x1574)) -#define PSX_INT(n, ecycle) \ - psxRegs.interrupt|= 1 << n; \ - g_psxNextBranchCycle = min(g_psxNextBranchCycle, psxRegs.cycle+ecycle); \ - psxRegs.sCycle[n] = psxRegs.cycle; \ - psxRegs.eCycle[n] = ecycle; - +extern void PSX_INT( int n, u32 ecycle); void psxHwReset(); u8 psxHwRead8 (u32 add); diff --git a/pcsx2/PsxInterpreter.c b/pcsx2/PsxInterpreter.c index 69431e84a7..32f399ee16 100644 --- a/pcsx2/PsxInterpreter.c +++ b/pcsx2/PsxInterpreter.c @@ -270,7 +270,7 @@ void zeroEx() { } } -#ifdef PSXBIOS_LOG +#ifdef PCSX2_DEVBUILD {char libz[9]; memcpy(libz, lib, 8); libz[8]=0; PSXBIOS_LOG("%s: %s (%x)" " (%x, %x, %x, %x)" //comment this line to disable param showing @@ -316,7 +316,7 @@ void zeroEx() { SysPrintf("sifcmd sceSifRegisterRpc (%x): rpc_id %x\n", psxRegs.pc, psxRegs.GPR.n.a1); } -#ifdef PSXBIOS_LOG +#ifdef PCSX2_DEVBUILD if (!strncmp(lib, "sysclib", 8)) { switch (code) { case 0x16: // strcmp @@ -330,7 +330,7 @@ void zeroEx() { } #endif -#ifdef PSXBIOS_LOG +#ifdef PCSX2_DEVBUILD if (varLog & 0x00800000) EMU_LOG("\n"); #endif @@ -387,7 +387,7 @@ void spyFunctions(){ * Format: OP rt, rs, immediate * *********************************************************/ void psxADDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im (Exception on Integer Overflow) -void psxADDIU() { if (!_Rt_) { zeroEx(); return; } _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im +void psxADDIU() { if (!_Rt_) { g_eeTightenSync+=3; zeroEx(); return; } _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im void psxANDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) & _ImmU_; } // Rt = Rs And Im void psxORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) | _ImmU_; } // Rt = Rs Or Im void psxXORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) ^ _ImmU_; } // Rt = Rs Xor Im @@ -774,7 +774,10 @@ extern void iDumpPsxRegisters(u32,u32); #endif static void intExecuteBlock() { - while (EEsCycle > 0){ + psxBreak = 0; + psxCycleEE = EEsCycle; + + while (psxCycleEE >= 0){ branch2 = 0; while (!branch2) { execI(); @@ -786,6 +789,7 @@ static void intExecuteBlock() { #endif } } + EEsCycle = psxBreak + psxCycleEE; } static void intClear(u32 Addr, u32 Size) { diff --git a/pcsx2/R3000A.c b/pcsx2/R3000A.c index 3a3067210a..4bb0732ee1 100644 --- a/pcsx2/R3000A.c +++ b/pcsx2/R3000A.c @@ -29,6 +29,17 @@ u32 g_psxConstRegs[32]; u32 g_psxHasConstReg, g_psxFlushedConstReg; u32 g_psxNextBranchCycle = 0; +// This value is used when the IOP execution is broken to return contorl to the EE. +// (which happens when the IOP throws EE-bound interrupts). It holds the value of +// psxCycleEE (which is set to zero to facilitate the code break), so that the unrun +// cycles can be accounted for later. +s32 psxBreak = 0; + +// tracks the IOP's current sync status with the EE. When it dips below zero, +// control is returned to the EE. +s32 psxCycleEE = -1; + + PCSX2_ALIGNED16(psxRegisters psxRegs); int psxInit() @@ -134,6 +145,36 @@ void psxException(u32 code, u32 bd) { }*/ } +__forceinline void PSX_INT( int n, u32 ecycle ) +{ + psxRegs.interrupt |= 1 << n; + + psxRegs.sCycle[n] = psxRegs.cycle; + psxRegs.eCycle[n] = ecycle; + + if( (g_psxNextBranchCycle - psxRegs.sCycle[n]) <= psxRegs.eCycle[n] ) return; + + // Interrupt is happening soon: make sure everyone is aware (includeing the EE!) + g_psxNextBranchCycle = psxRegs.sCycle[n] + psxRegs.eCycle[n]; + + if( psxCycleEE < 0 ) + { + // The EE called this int, so inform it to branch as needed: + + u32 iopDelta = (g_psxNextBranchCycle-psxRegs.cycle)*8; + if( g_nextBranchCycle - cpuRegs.cycle > iopDelta ) + { + // Optimization note: This method inlines witn 'n' as a constant, so the + // following conditionals will optimize nicely. + + g_nextBranchCycle = cpuRegs.cycle + iopDelta; + if( n > 12 ) g_eeTightenSync += 5; + if( n >= 19 ) g_eeTightenSync += 2; + } + } +} + + #define PSX_TESTINT(n, callback) \ if (psxRegs.interrupt & (1 << n)) { \ if ((int)(psxRegs.cycle - psxRegs.sCycle[n]) >= psxRegs.eCycle[n]) { \ @@ -143,46 +184,45 @@ void psxException(u32 code, u32 bd) { g_psxNextBranchCycle = psxRegs.sCycle[n] + psxRegs.eCycle[n]; \ } -static void _psxTestInterrupts() { +static __forceinline void _psxTestInterrupts() +{ PSX_TESTINT(9, sif0Interrupt); // SIF0 PSX_TESTINT(10, sif1Interrupt); // SIF1 - PSX_TESTINT(11, psxDMA11Interrupt); // SIO2 - PSX_TESTINT(12, psxDMA12Interrupt); // SIO2 PSX_TESTINT(16, sioInterrupt); - PSX_TESTINT(17, cdrInterrupt); - PSX_TESTINT(18, cdrReadInterrupt); PSX_TESTINT(19, cdvdReadInterrupt); - PSX_TESTINT(20, dev9Interrupt); - PSX_TESTINT(21, usbInterrupt); + + // Profile-guided Optimization (sorta) + // The following ints are rarely called. Encasing them in a conditional + // as follows helps speed up most games. + + if( psxRegs.interrupt & ( (3ul<<11) | (3ul<<20) | (3ul<<17) ) ) + { + PSX_TESTINT(17, cdrInterrupt); + PSX_TESTINT(18, cdrReadInterrupt); + PSX_TESTINT(11, psxDMA11Interrupt); // SIO2 + PSX_TESTINT(12, psxDMA12Interrupt); // SIO2 + PSX_TESTINT(20, dev9Interrupt); + PSX_TESTINT(21, usbInterrupt); + } } - -// IOP Wait cycles are still required to be a low number for maximum compatibility. -// Some games like to freeze up if the BranchTest isn't called at fairly regular -// intervals. ([TODO]: figure out why?) -#define IOP_WAIT_CYCLE 64 - void psxBranchTest() { - g_psxNextBranchCycle = psxRegs.cycle + IOP_WAIT_CYCLE; - - if ((int)(psxRegs.cycle - psxNextsCounter) >= psxNextCounter) + if ((psxRegs.cycle - psxNextsCounter) >= psxNextCounter) psxRcntUpdate(); - if (psxRegs.interrupt) { - _psxTestInterrupts(); - } + // start the next branch at the next counter event by default + // the int code below will assign nearer branches if needed. + g_psxNextBranchCycle = psxNextsCounter+psxNextCounter; - if( (int)(g_psxNextBranchCycle-psxNextsCounter) >= (u32)psxNextCounter ) - g_psxNextBranchCycle = (u32)psxNextsCounter+(u32)psxNextCounter; + if (psxRegs.interrupt) _psxTestInterrupts(); if (psxHu32(0x1078)) { if(psxHu32(0x1070) & psxHu32(0x1074)){ - if ((psxRegs.CP0.n.Status & 0xFE01) >= 0x401) { -//#ifdef PSXCPU_LOG -// PSXCPU_LOG("Interrupt: %x %x\n", HWMu32(0x1070), HWMu32(0x1074)); -//#endif + if ((psxRegs.CP0.n.Status & 0xFE01) >= 0x401) + { +// PSXCPU_LOG("Interrupt: %x %x\n", HWMu32(0x1070), HWMu32(0x1074)); psxException(0, 0); } } diff --git a/pcsx2/R3000A.h b/pcsx2/R3000A.h index 579fa1f858..e9b3065035 100644 --- a/pcsx2/R3000A.h +++ b/pcsx2/R3000A.h @@ -151,6 +151,9 @@ extern PCSX2_ALIGNED16_DECL(psxRegisters psxRegs); extern u32 g_psxConstRegs[32]; extern u32 g_psxHasConstReg, g_psxFlushedConstReg; +extern s32 psxBreak; // used when the IOP execution is broken and control returned to the EE +extern s32 psxCycleEE; // tracks IOP's current sych status with the EE + #ifndef _PC_ #define _i32(x) (s32)x @@ -197,7 +200,7 @@ extern u32 g_psxHasConstReg, g_psxFlushedConstReg; #define _SetLink(x) psxRegs.GPR.r[x] = _PC_ + 4; // Sets the return address in the link register -extern int EEsCycle; +extern s32 EEsCycle; extern u32 EEoCycle; #endif diff --git a/pcsx2/R5900.c b/pcsx2/R5900.c index c62c3cf8e3..5c98b49fb0 100644 --- a/pcsx2/R5900.c +++ b/pcsx2/R5900.c @@ -39,7 +39,7 @@ PCSX2_ALIGNED16(GPR_reg64 g_cpuConstRegs[32]) = {0}; u32 g_cpuHasConstReg = 0, g_cpuFlushedConstReg = 0; R5900cpu *Cpu; -int EEsCycle; // used to sync the IOP to the EE +s32 EEsCycle; // used to sync the IOP to the EE u32 EEoCycle; u32 bExecBIOS = 0; // set if the BIOS has already been executed @@ -325,34 +325,43 @@ void cpuTestMissingHwInts() { } } -#define TESTINT(n, callback) { \ - if ( (cpuRegs.interrupt & (1 << n)) ) { \ - if( ((int)(cpuRegs.cycle - cpuRegs.sCycle[n]) >= cpuRegs.eCycle[n]) ) { \ - callback(); \ - } \ - else if( (int)(g_nextBranchCycle - cpuRegs.sCycle[n]) > cpuRegs.eCycle[n] ) { \ - g_nextBranchCycle = cpuRegs.sCycle[n] + cpuRegs.eCycle[n]; \ - } \ - } \ -} \ +static __forceinline void TESTINT( u8 n, void (*callback)() ) +{ + if( !(cpuRegs.interrupt & (1 << n)) ) return; -void _cpuTestInterrupts() { + if( (cpuRegs.cycle - cpuRegs.sCycle[n]) >= cpuRegs.eCycle[n] ) + { + callback(); + } + else if( (g_nextBranchCycle - cpuRegs.sCycle[n]) > cpuRegs.eCycle[n] ) + g_nextBranchCycle = cpuRegs.sCycle[n] + cpuRegs.eCycle[n]; +} - inter = cpuRegs.interrupt; +static __forceinline void _cpuTestInterrupts() +{ /* These are 'pcsx2 interrupts', they handle asynchronous stuff that depends on the cycle timings */ - TESTINT(0, vif0Interrupt); - TESTINT(10, vifMFIFOInterrupt); TESTINT(1, vif1Interrupt); - TESTINT(11, gifMFIFOInterrupt); TESTINT(2, gsInterrupt); - TESTINT(3, ipu0Interrupt); - TESTINT(4, ipu1Interrupt); TESTINT(5, EEsif0Interrupt); TESTINT(6, EEsif1Interrupt); - TESTINT(8, SPRFROMinterrupt); - TESTINT(9, SPRTOinterrupt); + + // Profile-guided Optimization (sorta) + // The following ints are rarely called. Encasing them in a conditional + // as follows helps speed up most games. + + if( cpuRegs.interrupt & ( 1 | (3 << 3) | (3<<8) | (3<<10)) ) + { + TESTINT(0, vif0Interrupt); + TESTINT(3, ipu0Interrupt); + TESTINT(4, ipu1Interrupt); + TESTINT(8, SPRFROMinterrupt); + TESTINT(9, SPRTOinterrupt); + + TESTINT(10, vifMFIFOInterrupt); + TESTINT(11, gifMFIFOInterrupt); + } if ((cpuRegs.CP0.n.Status.val & 0x10007) != 0x10001) return; TESTINT(30, intcInterrupt); @@ -362,10 +371,17 @@ void _cpuTestInterrupts() { u32 s_iLastCOP0Cycle = 0; u32 s_iLastPERFCycle[2] = {0,0}; -_inline static void _cpuTestTIMR() { +static __forceinline void _cpuTestTIMR() +{ cpuRegs.CP0.n.Count += cpuRegs.cycle-s_iLastCOP0Cycle; s_iLastCOP0Cycle = cpuRegs.cycle; + // [Air] : Are these necessary? The recompiler and interpreter code both appear + // to recalculate them whenever they're read. (although if they were not read + // for a long time they could overflow). Maybe these checks could be moved to + // the Ints or Counters so they they get called less frequently, but still get + // called enough to avoid overflows. + if((cpuRegs.PERF.n.pccr & 0x800003E0) == 0x80000020) { cpuRegs.PERF.n.pcr0 += cpuRegs.cycle-s_iLastPERFCycle[0]; s_iLastPERFCycle[0] = cpuRegs.cycle; @@ -382,41 +398,71 @@ _inline static void _cpuTestTIMR() { } } +// maximum wait between branches. Lower values provide a tighter synchronization between +// the EE and the IOP, but incur more execution overhead. #define EE_WAIT_CYCLE 2048 +// maximum wait between branches when EE/IOP sync is tightened via g_eeTightenSync. +// Lower values don't always make games better, since places where this value is set +// will have to use higher numbers to achieve the same cycle count. +#define EE_ACTIVE_CYCLE 192 +#define EE_ACTIVE_CYCLE_SUB (EE_WAIT_CYCLE - EE_ACTIVE_CYCLE) + + // if cpuRegs.cycle is greater than this cycle, should check cpuBranchTest for updates u32 g_nextBranchCycle = 0; -u32 s_lastvsync[2]; + +// if non-zero, the EE uses a shorter wait cycle (effectively tightening EE/IOP code +// synchronization). Value decremented each branch test. +u32 g_eeTightenSync = 0; + +#if !defined( PCSX2_NORECBUILD ) && !defined( PCSX2_PUBLIC ) extern u8 g_globalXMMSaved; X86_32CODE(extern u8 g_globalMMXSaved;) +#endif -u32 loaded = 0; u32 g_MTGSVifStart = 0, g_MTGSVifCount=0; extern void gsWaitGS(); void cpuBranchTest() { #ifndef PCSX2_NORECBUILD +#ifndef PCSX2_PUBLIC // dont' remove this check unless doing an official release if( g_globalXMMSaved X86_32CODE(|| g_globalMMXSaved) ) SysPrintf("frozen regs have not been restored!!!\n"); assert( !g_globalXMMSaved X86_32CODE(&& !g_globalMMXSaved) ); +#endif g_EEFreezeRegs = 0; #endif -// if( !loaded && cpuRegs.cycle > 0x20000000 ) { -// char strstate[255]; -// sprintf(strstate, SSTATES_DIR "/%8.8X.000", ElfCRC); -// LoadState(strstate); -// loaded = 1; -// } - g_nextBranchCycle = cpuRegs.cycle + EE_WAIT_CYCLE; + if( g_eeTightenSync != 0 ) + { + // This means we're running "sync-sensitive" code. + // tighten up the EE's cycle rate to ensure a more responsive + // EE/IOP operation: - if ((int)(cpuRegs.cycle - nextsCounter) >= nextCounter) + g_eeTightenSync--; + g_nextBranchCycle -= EE_ACTIVE_CYCLE_SUB; + } + + // ---- Counters ------------- + + if( (cpuRegs.cycle - nextsCounter) >= nextCounter ) rcntUpdate(); - // stall mtgs if it is taking too long + if( (g_nextBranchCycle-nextsCounter) >= nextCounter ) + g_nextBranchCycle = nextsCounter+nextCounter; + + // ---- Interrupts ------------- + + if( cpuRegs.interrupt ) + _cpuTestInterrupts(); + + // ---- MTGS ------------- + // stall mtgs if it is taking too long + if( g_MTGSVifCount > 0 ) { if( cpuRegs.cycle-g_MTGSVifStart > g_MTGSVifCount ) { gsWaitGS(); @@ -424,25 +470,17 @@ void cpuBranchTest() } } - if (cpuRegs.interrupt) - _cpuTestInterrupts(); - - if( (int)(g_nextBranchCycle-nextsCounter) >= nextCounter ) - g_nextBranchCycle = nextsCounter+nextCounter; - //#ifdef CPU_LOG // cpuTestMissingHwInts(); //#endif _cpuTestTIMR(); // ---- IOP ------------- - // Signal for an immediate branch test! This is important! The IOP must // be able to act on the state the EE has given it before executing any - // additional code. Doing this actually fixes some games that used to crash - // when trying to boot them through the BIOS. + // additional code. - //psxBranchTest(); + psxBranchTest(); EEsCycle += cpuRegs.cycle - EEoCycle; EEoCycle = cpuRegs.cycle; @@ -461,30 +499,56 @@ void cpuBranchTest() // ---- VU0 ------------- - if (VU0.VI[REG_VPU_STAT].UL & 0x1) { + if (VU0.VI[REG_VPU_STAT].UL & 0x1) + { FreezeXMMRegs(1); Cpu->ExecuteVU0Block(); FreezeXMMRegs(0); } - // [Air] dead code? There shouldn't be any reason to bother checking - // for g_nextBranchCycle being behind cpuRegs.cycle, since the branch code will - // just do the same check after the next block. - - //if( (int)cpuRegs.cycle-(int)g_nextBranchCycle > 0 ) - // g_nextBranchCycle = cpuRegs.cycle+1; - #ifndef PCSX2_NORECBUILD +#ifndef PCSX2_PUBLIC assert( !g_globalXMMSaved X86_32CODE(&& !g_globalMMXSaved) ); +#endif g_EEFreezeRegs = 1; #endif } +__forceinline void CPU_INT( u32 n, u32 ecycle) +{ + cpuRegs.interrupt|= 1 << n; + cpuRegs.sCycle[n] = cpuRegs.cycle; + cpuRegs.eCycle[n] = ecycle; + + if( (g_nextBranchCycle - cpuRegs.sCycle[n]) <= cpuRegs.eCycle[n] ) return; + + // Interrupt is happening soon: make sure everyone's aware! + g_nextBranchCycle = cpuRegs.sCycle[n] + cpuRegs.eCycle[n]; + + // Optimization note: this method inlines nicely since 'n' is almost always a + // constant. The following conditional optimizes to virtually nothing in most + // cases. + + if( ( n == 3 || n == 4 || n == 30 || n == 31 ) && + ecycle <= 28 && psxCycleEE > 0 ) + { + // If running in the IOP, force it to break immediately into the EE. + // the EE's branch test is due to run. + + psxBreak += psxCycleEE; // number of cycles we didn't run. + psxCycleEE = 0; + if( n == 3 || n == 4 ) + g_eeTightenSync += 1; // only tighten IPU a bit, otherwise it's too slow! + else + g_eeTightenSync += 4; + } +} + static void _cpuTestINTC() { if ((cpuRegs.CP0.n.Status.val & 0x10407) == 0x10401){ if (psHu32(INTC_STAT) & psHu32(INTC_MASK)) { if ((cpuRegs.interrupt & (1 << 30)) == 0) { - INT(30,4); + CPU_INT(30,4); } } } @@ -495,7 +559,7 @@ static void _cpuTestDMAC() { if (psHu16(0xe012) & psHu16(0xe010) || psHu16(0xe010) & 0x8000) { if ( (cpuRegs.interrupt & (1 << 31)) == 0) { - INT(31, 4); + CPU_INT(31, 4); } } } @@ -623,15 +687,16 @@ void IntcpuBranchTest() g_EEFreezeRegs = 0; #endif - g_nextBranchCycle = cpuRegs.cycle + EE_WAIT_CYCLE; + // Interpreter uses a high-resolution wait cycle all the time: + g_nextBranchCycle = cpuRegs.cycle + 256; - if ((int)(cpuRegs.cycle - nextsCounter) >= nextCounter) + if ((cpuRegs.cycle - nextsCounter) >= nextCounter) rcntUpdate(); if (cpuRegs.interrupt) _cpuTestInterrupts(); - if( (int)(g_nextBranchCycle-nextsCounter) >= nextCounter ) + if( (g_nextBranchCycle-nextsCounter) >= nextCounter ) g_nextBranchCycle = nextsCounter+nextCounter; //#ifdef CPU_LOG @@ -639,6 +704,8 @@ void IntcpuBranchTest() //#endif _cpuTestTIMR(); + psxBranchTest(); + EEsCycle += cpuRegs.cycle - EEoCycle; EEoCycle = cpuRegs.cycle; @@ -651,9 +718,6 @@ void IntcpuBranchTest() Cpu->ExecuteVU1Block(); } - if( (int)cpuRegs.cycle-(int)g_nextBranchCycle > 0 ) - g_nextBranchCycle = cpuRegs.cycle+1; - #ifndef PCSX2_NORECBUILD g_EEFreezeRegs = 1; #endif diff --git a/pcsx2/R5900.h b/pcsx2/R5900.h index f620944b25..5911189bdc 100644 --- a/pcsx2/R5900.h +++ b/pcsx2/R5900.h @@ -125,7 +125,7 @@ typedef struct { u32 tempcycles; } cpuRegisters; -extern int EEsCycle; +extern s32 EEsCycle; extern u32 EEoCycle; extern PCSX2_ALIGNED16_DECL(cpuRegisters cpuRegs); @@ -236,7 +236,6 @@ void cpuTestHwInts(); void cpuTestINTCInts(); void cpuTestDMACInts(); void cpuTestTIMRInts(); -void _cpuTestInterrupts(); void cpuExecuteBios(); void cpuRestartCPU(); @@ -252,6 +251,7 @@ void JumpCheckSym(u32 addr, u32 pc); void JumpCheckSymRet(u32 addr); extern u32 g_EEFreezeRegs; +extern u32 g_eeTightenSync; // non-zero values tighten EE/IOP code synchronization for short periods. //exception code #define EXC_CODE(x) ((x)<<2) diff --git a/pcsx2/SPR.c b/pcsx2/SPR.c index db1cfdfcc7..7d4d6c61f9 100644 --- a/pcsx2/SPR.c +++ b/pcsx2/SPR.c @@ -127,7 +127,7 @@ void _SPR0interleave() { } spr0->qwc = 0; - INT(8, cycles); + CPU_INT(8, cycles); } void _dmaSPR0() { @@ -146,7 +146,7 @@ void _dmaSPR0() { if ((spr0->chcr & 0xc) == 0x0) { // Normal Mode int cycles = 0; SPR0chain(); - INT(8, cycles); + CPU_INT(8, cycles); return; } else if ((spr0->chcr & 0xc) == 0x4) { @@ -157,7 +157,7 @@ void _dmaSPR0() { if(spr0->qwc > 0){ SPR0chain(); - INT(8, cycles); + CPU_INT(8, cycles); return; } @@ -214,7 +214,7 @@ void _dmaSPR0() { return; }*/ } - INT(8, cycles); + CPU_INT(8, cycles); } else { // Interleave Mode _SPR0interleave(); } @@ -314,7 +314,7 @@ void _SPR1interleave() { } spr1->qwc = 0; - INT(9, cycles); + CPU_INT(9, cycles); } @@ -337,7 +337,7 @@ void dmaSPR1() { // toSPR //if(spr1->qwc == 0 && (spr1->chcr & 0xc) == 1) spr1->qwc = 0xffff; // Transfer Dn_QWC from Dn_MADR to SPR1 SPR1chain(); - INT(9, cycles); + CPU_INT(9, cycles); FreezeMMXRegs(0); return; } else if ((spr1->chcr & 0xc) == 0x4){ @@ -350,7 +350,7 @@ void dmaSPR1() { // toSPR //if(spr1->qwc == 0 && (spr1->chcr & 0xc) == 1) spr1->qwc = 0xffff; // Transfer Dn_QWC from Dn_MADR to SPR1 SPR1chain(); - INT(9, cycles); + CPU_INT(9, cycles); FreezeMMXRegs(0); return; } @@ -399,7 +399,7 @@ void dmaSPR1() { // toSPR break; } } - INT(9, cycles); + CPU_INT(9, cycles); } else { // Interleave Mode _SPR1interleave(); } diff --git a/pcsx2/Sif.c b/pcsx2/Sif.c index 1723d8d5c0..5515eab67f 100644 --- a/pcsx2/Sif.c +++ b/pcsx2/Sif.c @@ -277,7 +277,7 @@ _inline void SIF0Dma() //sif0dma->chcr &= ~0x100; eesifbusy[0] = 0; - INT(5, cycles*BIAS); + CPU_INT(5, cycles*BIAS); //hwDmacIrq(5); notDone = 0; } @@ -289,7 +289,7 @@ _inline void SIF0Dma() //sif0dma->chcr &= ~0x100; //hwDmacIrq(5); eesifbusy[0] = 0; - INT(5, cycles*BIAS); + CPU_INT(5, cycles*BIAS); notDone = 0; } else if(sif0.fifoSize >= 4) // Read a tag @@ -344,7 +344,7 @@ _inline void SIF1Dma() SIF_LOG("EE SIF1 End %x\n", sif1.end); eesifbusy[1] = 0; notDone = 0; - INT(6, cycles*BIAS); + CPU_INT(6, cycles*BIAS); sif1.chain = 0; sif1.end = 0; } @@ -519,7 +519,7 @@ _inline void sif1Interrupt() { _inline void EEsif0Interrupt() { /*if (psHu32(DMAC_STAT) & (1<<5)) { - INT(5, 0x800); + CPU_INT(5, 0x800); return 0; }*/ sif0dma->chcr &= ~0x100; @@ -531,7 +531,7 @@ _inline void EEsif0Interrupt() { _inline void EEsif1Interrupt() { /*if (psHu32(DMAC_STAT) & (1<<6)) { - INT(6, 0x800); + CPU_INT(6, 0x800); return 0; }*/ hwDmacIrq(6); diff --git a/pcsx2/Vif.c b/pcsx2/Vif.c index 2d614804f8..7917df1815 100644 --- a/pcsx2/Vif.c +++ b/pcsx2/Vif.c @@ -521,7 +521,7 @@ void mfifoVIF1transfer(int qwc) { VIF_LOG("MFIFO Stallon tag\n"); #endif vif1.stallontag = 1; - INT(10,cycles+g_vifCycles); + CPU_INT(10,cycles+g_vifCycles); return; //IRQ set by VIFTransfer } } @@ -584,20 +584,20 @@ void mfifoVIF1transfer(int qwc) { SysPrintf("VIF dmaChain error size=%d, madr=%lx, tadr=%lx\n", vif1ch->qwc, vif1ch->madr, vif1ch->tadr); vif1.done = 1; - INT(10,g_vifCycles); + CPU_INT(10,g_vifCycles); } if(ret == -2){ #ifdef VIF_LOG VIF_LOG("MFIFO Stall\n"); #endif - INT(10,g_vifCycles); + CPU_INT(10,g_vifCycles); return; } if(vif1.done == 2 && vif1ch->qwc == 0) vif1.done = 1; - INT(10,g_vifCycles); + CPU_INT(10,g_vifCycles); #ifdef SPR_LOG SPR_LOG("mfifoVIF1transfer end %x madr %x, tadr %x vifqwc %x\n", vif1ch->chcr, vif1ch->madr, vif1ch->tadr, vifqwc); diff --git a/pcsx2/VifDma.c b/pcsx2/VifDma.c index 028e5d3f0f..f37c100f82 100644 --- a/pcsx2/VifDma.c +++ b/pcsx2/VifDma.c @@ -1293,7 +1293,7 @@ void vif0Interrupt() { _chainVIF0(); } else _VIF0chain(); - INT(0, g_vifCycles); + CPU_INT(0, g_vifCycles); return; } } @@ -1318,7 +1318,7 @@ void vif0Interrupt() { if(vif0ch->qwc > 0) _VIF0chain(); ret = _chainVIF0(); - INT(0, g_vifCycles); + CPU_INT(0, g_vifCycles); return; //if(ret!=2) /*else*/ //return 1; @@ -1387,7 +1387,7 @@ void dmaVIF0() { }*/ // if(vif0ch->qwc > 0) { // _VIF0chain(); -// INT(0, g_vifCycles); +// CPU_INT(0, g_vifCycles); // } g_vifCycles = 0; @@ -1401,17 +1401,17 @@ void dmaVIF0() { return; } vif0.done = 1; - INT(0, g_vifCycles); + CPU_INT(0, g_vifCycles); return; } /* if (_VIF0chain() != 0) { - INT(0, g_vifCycles); + CPU_INT(0, g_vifCycles); return; }*/ // Chain Mode vif0.done = 0; - INT(0, g_vifCycles); + CPU_INT(0, g_vifCycles); } @@ -1477,7 +1477,7 @@ void vif0Write32(u32 mem, u32 value) { } else _VIF0chain(); vif0ch->chcr |= 0x100; - INT(0, g_vifCycles); // Gets the timing right - Flatout + CPU_INT(0, g_vifCycles); // Gets the timing right - Flatout } } } @@ -1839,7 +1839,7 @@ static void Vif1CMDMskPath3(){ // MSKPATH3 //while(gif->chcr & 0x100) gsInterrupt(); // Finish the transfer first psHu32(GIF_STAT) |= 0x2; } else { - if(gif->chcr & 0x100) INT(2, (transferred>>2) * BIAS); // Restart Path3 on its own, time it right! + if(gif->chcr & 0x100) CPU_INT(2, (transferred>>2) * BIAS); // Restart Path3 on its own, time it right! psHu32(GIF_STAT) &= ~0x2; } #else @@ -2230,7 +2230,7 @@ void vif1Interrupt() { _chainVIF1(); } else _VIF1chain(); - INT(1, g_vifCycles); + CPU_INT(1, g_vifCycles); return; } } @@ -2249,7 +2249,7 @@ void vif1Interrupt() { } /*if(vif1ch->qwc > 0){ _VIF1chain(); - INT(1, g_vifCycles); + CPU_INT(1, g_vifCycles); return 0; }*/ if ((vif1ch->chcr & 0x104) == 0x104 && vif1.done == 0) { @@ -2260,7 +2260,7 @@ void vif1Interrupt() { } _chainVIF1(); - INT(1, g_vifCycles); + CPU_INT(1, g_vifCycles); return; } @@ -2302,7 +2302,7 @@ void dmaVIF1() }*/ // if(vif1ch->qwc > 0) { // _VIF1chain(); -// INT(1, g_vifCycles); +// CPU_INT(1, g_vifCycles); // } vif1.done = 0; g_vifCycles = 0; @@ -2321,11 +2321,11 @@ void dmaVIF1() VIF_LOG("dmaIrq Set\n"); #endif vif1.done = 1; - INT(1, g_vifCycles); + CPU_INT(1, g_vifCycles); return; } //vif1.done = 1; - INT(1, g_vifCycles); + CPU_INT(1, g_vifCycles); return; }*/ @@ -2356,7 +2356,7 @@ void dmaVIF1() vif1.vifstalled = 1; return; } - INT(1, g_vifCycles); + CPU_INT(1, g_vifCycles); } else { // from Memory @@ -2401,7 +2401,7 @@ void dmaVIF1() vif1.done = 1; vif1Regs->stat&= ~0x1f000000; vif1ch->qwc = 0; - INT(1, g_vifCycles); + CPU_INT(1, g_vifCycles); return; //Return -1 as an error has occurred } @@ -2427,7 +2427,7 @@ void dmaVIF1() g_vifCycles += vif1ch->qwc * 2; vif1ch->madr += vif1ch->qwc * 16; // mgs3 scene changes vif1ch->qwc = 0; - INT(1, g_vifCycles); + CPU_INT(1, g_vifCycles); } } @@ -2437,13 +2437,13 @@ void dmaVIF1() } /* if (_VIF1chain() != 0) { - INT(1, g_vifCycles); + CPU_INT(1, g_vifCycles); return; }*/ // Chain Mode vif1.done = 0; - INT(1, g_vifCycles); + CPU_INT(1, g_vifCycles); } @@ -2509,14 +2509,14 @@ void vif1Write32(u32 mem, u32 value) { if((psHu32(DMAC_CTRL) & 0xC) == 0x8){ //vif1.vifstalled = 0; //SysPrintf("MFIFO Stall\n"); - INT(10, 0); + CPU_INT(10, 0); }else { if(vif1.stallontag == 1){ //SysPrintf("Sorting VIF Stall on tag\n"); _chainVIF1(); } else _VIF1chain(); //vif1.vifstalled = 0' - INT(1, g_vifCycles); // Gets the timing right - Flatout + CPU_INT(1, g_vifCycles); // Gets the timing right - Flatout } vif1ch->chcr |= 0x100; } diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index 508406ad1a..f8d9ea6828 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -359,6 +359,7 @@ GameFixes = strtoul(szValue, NULL, 0); + // Remove Fast Branches hack for now: + Conf->Hacks &= ~0x80; + #ifdef ENABLE_NLS { char text[256]; diff --git a/pcsx2/windows/pcsx2.rc b/pcsx2/windows/pcsx2.rc index 87f56aab46..79789d198d 100644 --- a/pcsx2/windows/pcsx2.rc +++ b/pcsx2/windows/pcsx2.rc @@ -1058,7 +1058,7 @@ BEGIN CONTROL "Disable FPU Overflow Checks - *Checked = Disables overflow checks. ( Speedup! ) *Greyed = Extra overflow checks. ( Helps SPS, Slow! )",IDC_FPU_OVERFLOWHACK, "Button",BS_AUTO3STATE | WS_TABSTOP,15,63,483,10 CONTROL "EE/IOP Fast Branches - Quick branching ( Very small speedup; Not Recommended! )",IDC_FASTBRANCHES, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,231,423,10 + "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,15,231,423,10 CTEXT "If you have problems, disable all these and try again!",IDC_STATIC,7,22,497,8 GROUPBOX "Overflow and Underflow",IDC_STATIC,7,36,497,58 CONTROL "Disable Underflow Checks - *Checked = Disables underflow checks. ( Speedup! )",IDC_DENORMALS, diff --git a/pcsx2/x86/iR3000A.cpp b/pcsx2/x86/iR3000A.cpp index d96fea6494..e9dd16aac9 100644 --- a/pcsx2/x86/iR3000A.cpp +++ b/pcsx2/x86/iR3000A.cpp @@ -445,20 +445,26 @@ void psxRecompileCodeConst0(R3000AFNPTR constcode, R3000AFNPTR_INFO constscode, } extern "C" void zeroEx(); +extern "C" u32 g_eeTightenSync; // rt = rs op imm16 void psxRecompileCodeConst1(R3000AFNPTR constcode, R3000AFNPTR_INFO noconstcode) { if ( ! _Rt_ ) { -#ifdef _DEBUG if( (psxRegs.code>>26) == 9 ) { //ADDIU, call bios +#ifdef _DEBUG MOV32ItoM( (uptr)&psxRegs.code, psxRegs.code ); MOV32ItoM( (uptr)&psxRegs.pc, psxpc ); _psxFlushCall(FLUSH_NODESTROY); CALLFunc((uptr)zeroEx); - } #endif + // Tighten up the EE/IOP sync (helps prevent crashes) + // [TODO] should probably invoke a branch test or EE code control break here, + // but it would require the use of registers and I have no eff'ing idea how + // the register allocation stuff works in the recompiler. :/ + ADD32ItoM( (uptr)&g_eeTightenSync, 3 ); + } return; } @@ -618,7 +624,7 @@ static void recShutdown() { #if !defined(__x86_64__) static u32 s_uSaveESP = 0; -static void R3000AExecute() +static __forceinline void R3000AExecute() { #ifdef _DEBUG u8* fnptr; @@ -629,7 +635,8 @@ static void R3000AExecute() BASEBLOCK* pblock; - while (EEsCycle > 0) { + //while (EEsCycle > 0) + { pblock = PSX_GETBLOCK(psxRegs.pc); if ( !pblock->pFnptr || (pblock->startpc&PSX_MEMMASK) != (psxRegs.pc&PSX_MEMMASK) ) { @@ -983,9 +990,6 @@ void psxSetBranchImm( u32 imm ) #define USE_FAST_BRANCHES CHECK_FASTBRANCHES -// Important! The following macro makes sure the rounding error of both the psxRegs.cycle -// modifier and EEsCycle modifier are consistent (in case you wonder why it's got a u32 typecast) - //fixme : this is all a huge hack, we base the counter advancements on the average an opcode should take (wtf?) // If that wasn't bad enough we have default values like 9/8 which will get cast to int later // (yeah, that means all sync code couldn't have worked to beginn with) @@ -1000,29 +1004,35 @@ static u32 psxScaleBlockCycles() (CHECK_IOPSYNC_HACK ? (CHECK_EE_IOP_EXTRA ? 3 : 2) : 1 ); } +extern "C" s32 psxScaleWaitCycles() +{ + return -40 * + (CHECK_IOPSYNC_HACK ? (CHECK_EE_IOP_EXTRA ? 3.1875 : 2.125) : (17/16)); +} + + static void iPsxBranchTest(u32 newpc, u32 cpuBranch) { u32 blockCycles = psxScaleBlockCycles(); if( USE_FAST_BRANCHES && cpuBranch == 0 ) { - SUB32ItoM((uptr)&EEsCycle, blockCycles*8 ); + SUB32ItoM((uptr)&psxCycleEE, blockCycles*8 ); ADD32ItoM((uptr)&psxRegs.cycle, blockCycles); return; } MOV32MtoR(ECX, (uptr)&psxRegs.cycle); - ADD32ItoR(ECX, blockCycles); // greater mult factor causes nfsmw to crash + MOV32MtoR(EAX, (uptr)&psxCycleEE); + ADD32ItoR(ECX, blockCycles); + SUB32ItoR(EAX, blockCycles*8); MOV32RtoM((uptr)&psxRegs.cycle, ECX); // update cycles + MOV32RtoM((uptr)&psxCycleEE, EAX); - // check if we've caught up with the EE - SUB32ItoM((uptr)&EEsCycle, blockCycles*8 ); - j8Ptr[2] = JGE8(0); - - // Break the Block-execute Loop here. + j8Ptr[2] = JNS8( 0 ); // jump if no, on (psxCycleEE - blockCycles*8) < 0 if( REC_INC_STACK ) ADD64ItoR(ESP, REC_INC_STACK); - RET2(); + RET2(); // returns control to the EE // Continue onward with branching here: x86SetJ8( j8Ptr[2] ); @@ -1033,7 +1043,8 @@ static void iPsxBranchTest(u32 newpc, u32 cpuBranch) CALLFunc((uptr)psxBranchTest); - if( newpc != 0xffffffff ) { + if( newpc != 0xffffffff ) + { CMP32ItoM((uptr)&psxRegs.pc, newpc); JNE32((uptr)psxDispatcherReg - ( (uptr)x86Ptr + 6 )); } @@ -1069,7 +1080,7 @@ void rpsxSYSCALL() CMP32ItoM((uptr)&psxRegs.pc, psxpc-4); j8Ptr[0] = JE8(0); ADD32ItoM((uptr)&psxRegs.cycle, psxScaleBlockCycles() ); - SUB32ItoM((uptr)&EEsCycle, psxScaleBlockCycles()*8 ); + SUB32ItoM((uptr)&psxCycleEE, psxScaleBlockCycles()*8 ); JMP32((uptr)psxDispatcherReg - ( (uptr)x86Ptr + 5 )); x86SetJ8(j8Ptr[0]); @@ -1088,7 +1099,7 @@ void rpsxBREAK() CMP32ItoM((uptr)&psxRegs.pc, psxpc-4); j8Ptr[0] = JE8(0); ADD32ItoM((uptr)&psxRegs.cycle, psxScaleBlockCycles() ); - SUB32ItoM((uptr)&EEsCycle, psxScaleBlockCycles()*8 ); + SUB32ItoM((uptr)&psxCycleEE, psxScaleBlockCycles()*8 ); JMP32((uptr)psxDispatcherReg - ( (uptr)x86Ptr + 5 )); x86SetJ8(j8Ptr[0]); @@ -1113,6 +1124,9 @@ void psxRecompileNextInstruction(int delayslot) BASEBLOCK* pblock = PSX_GETBLOCK(psxpc); + //if( psxpc == 0x5264 ) + // SysPrintf( "Woot!" ); + // need *ppblock != s_pCurBlock because of branches if( pblock->pFnptr != 0 && pblock->startpc != s_pCurBlock->startpc ) { @@ -1200,8 +1214,12 @@ static void recExecute() { for (;;) R3000AExecute(); } -static void recExecuteBlock() { +static void recExecuteBlock() +{ + psxBreak = 0; + psxCycleEE = EEsCycle; R3000AExecute(); + EEsCycle = psxBreak + psxCycleEE; } #include "PsxHw.h" @@ -1511,7 +1529,7 @@ StartRecomp: else { ADD32ItoM((uptr)&psxRegs.cycle, psxScaleBlockCycles() ); - SUB32ItoM((uptr)&EEsCycle, psxScaleBlockCycles()*8 ); + SUB32ItoM((uptr)&psxCycleEE, psxScaleBlockCycles()*8 ); } if( willbranch3 ) { diff --git a/pcsx2/x86/ix86-32/iR5900-32.c b/pcsx2/x86/ix86-32/iR5900-32.c index ebbb24a00c..05dc252cb3 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.c +++ b/pcsx2/x86/ix86-32/iR5900-32.c @@ -2258,7 +2258,6 @@ void iFlushCall(int flushtype) // So for now these are new settings that work. I would've set 1 for default but that seemed too low // (rama) -//#define EECYCLE_MULT (CHECK_EESYNC_HACK ? (CHECK_EE_IOP_EXTRA ? 3.375 : 2.25) : (9/8)) #define EECYCLE_MULT (CHECK_EESYNC_HACK ? (CHECK_EE_IOP_EXTRA ? 3 : 2) : (1.2)) static void iBranchTest(u32 newpc, u32 cpuBranch) @@ -2274,26 +2273,26 @@ static void iBranchTest(u32 newpc, u32 cpuBranch) //CALLFunc((uptr)testfpu); #endif - if( !USE_FAST_BRANCHES || cpuBranch ) { - MOV32MtoR(ECX, (int)&cpuRegs.cycle); - ADD32ItoR(ECX, s_nBlockCycles*EECYCLE_MULT); // NOTE: mulitply cycles here, 6/5 ratio stops pal ffx from randomly crashing, but crashes jakI - MOV32RtoM((int)&cpuRegs.cycle, ECX); // update cycles - } - else { - ADD32ItoM((int)&cpuRegs.cycle, s_nBlockCycles*EECYCLE_MULT); + if( USE_FAST_BRANCHES && (cpuBranch==0) ) + { + ADD32ItoM((uptr)&cpuRegs.cycle, s_nBlockCycles*EECYCLE_MULT); return; } - SUB32MtoR(ECX, (int)&g_nextBranchCycle); + MOV32MtoR(ECX, (uptr)&cpuRegs.cycle); + ADD32ItoR(ECX, s_nBlockCycles*EECYCLE_MULT); + MOV32RtoM((uptr)&cpuRegs.cycle, ECX); // update cycles + SUB32MtoR(ECX, (uptr)&g_nextBranchCycle); // check if should branch j8Ptr[0] = JS8( 0 ); // has to be in the middle of Save/LoadBranchState - CALLFunc( (int)cpuBranchTest ); + CALLFunc( (uptr)cpuBranchTest ); - if( newpc != 0xffffffff ) { - CMP32ItoM((int)&cpuRegs.pc, newpc); + if( newpc != 0xffffffff ) + { + CMP32ItoM((uptr)&cpuRegs.pc, newpc); JNE32((u32)DispatcherReg - ( (u32)x86Ptr + 6 )); } @@ -2325,9 +2324,9 @@ void recSYSCALL( void ) { iFlushCall(FLUSH_NODESTROY); CALLFunc( (uptr)SYSCALL ); - CMP32ItoM((int)&cpuRegs.pc, pc); + CMP32ItoM((uptr)&cpuRegs.pc, pc); j8Ptr[0] = JE8(0); - ADD32ItoM((u32)&cpuRegs.cycle, s_nBlockCycles*EECYCLE_MULT); + ADD32ItoM((uptr)&cpuRegs.cycle, s_nBlockCycles*EECYCLE_MULT); JMP32((u32)DispatcherReg - ( (u32)x86Ptr + 5 )); x86SetJ8(j8Ptr[0]); //branch = 2; @@ -2340,7 +2339,7 @@ void recBREAK( void ) { iFlushCall(FLUSH_EVERYTHING); CALLFunc( (uptr)BREAK ); - CMP32ItoM((int)&cpuRegs.pc, pc); + CMP32ItoM((uptr)&cpuRegs.pc, pc); j8Ptr[0] = JE8(0); ADD32ItoM((u32)&cpuRegs.cycle, s_nBlockCycles*EECYCLE_MULT); RET();