static __fi void Sif2End() { psHu32(SBUS_F240) &= ~0x80; psHu32(SBUS_F240) &= ~0x8000; DMA_LOG("SIF2 DMA End"); }
static __fi void Sif1End() { psHu32(SBUS_F240) &= ~0x40; psHu32(SBUS_F240) &= ~0x4000; DMA_LOG("SIF1 DMA End"); }
static __fi void Sif0End() { psHu32(SBUS_F240) &= ~0x20; psHu32(SBUS_F240) &= ~0x2000; DMA_LOG("SIF0 DMA End"); }
__fi void dmaSIF2() { DevCon.Warning("SIF2 EE CHCR %x", sif2dma.chcr._u32); SIF_LOG(wxString(L"dmaSIF2" + sif2dma.cmqt_to_str()).To8BitData()); if (sif2.fifo.readPos != sif2.fifo.writePos) { SIF_LOG("warning, sif2.fifoReadPos != sif2.fifoWritePos"); } //if(sif2dma.chcr.MOD == CHAIN_MODE && sif2dma.qwc > 0) DevCon.Warning(L"SIF2 QWC on Chain CHCR " + sif2dma.chcr.desc()); psHu32(SBUS_F240) |= 0x8000; sif2.ee.busy = true; // Okay, this here is needed currently (r3644). // FFX battles in the thunder plains map die otherwise, Phantasy Star 4 as well // These 2 games could be made playable again by increasing the time the EE or the IOP run, // showing that this is very timing sensible. // Doing this DMA unfortunately brings back an old warning in Legend of Legaia though, but it still works. //Updated 23/08/2011: The hangs are caused by the EE suspending SIF1 DMA and restarting it when in the middle //of processing a "REFE" tag, so the hangs can be solved by forcing the ee.end to be false // (as it should always be at the beginning of a DMA). using "if iop is busy" flags breaks Tom Clancy Rainbow Six. // Legend of Legaia doesn't throw a warning either :) //sif2.ee.end = false; SIF2Dma(); }
// emits "setup" code for a COP0 branch test. The instruction immediately following // this should be a conditional Jump -- JZ or JNZ normally. static void _setupBranchTest() { _eeFlushAllUnused(); // COP0 branch conditionals are based on the following equation: // (((psHu16(DMAC_STAT) | ~psHu16(DMAC_PCR)) & 0x3ff) == 0x3ff) // BC0F checks if the statement is false, BC0T checks if the statement is true. // note: We only want to compare the 16 bit values of DMAC_STAT and PCR. // But using 32-bit loads here is ok (and faster), because we mask off // everything except the lower 10 bits away. xMOV(eax, ptr[(&psHu32(DMAC_PCR) )]); xMOV(ecx, 0x3ff ); // ECX is our 10-bit mask var xNOT(eax); xOR(eax, ptr[(&psHu32(DMAC_STAT) )]); xAND(eax, ecx); xCMP(eax, ecx); }
__fi u32 dmacRead32( u32 mem ) { // Fixme: OPH hack. Toggle the flag on each GIF_STAT access. (rama) if (IsPageFor(mem) && (mem == GIF_STAT) && CHECK_OPHFLAGHACK) { gifRegs.stat.OPH = !gifRegs.stat.OPH; } return psHu32(mem); }
// Returns true if the DMA is enabled and executed successfully. Returns false if execution // was blocked (DMAE or master DMA enabler). static bool QuickDmaExec( void (*func)(), u32 mem) { bool ret = false; DMACh& reg = (DMACh&)psHu32(mem); if (reg.chcr.STR && dmacRegs.ctrl.DMAE && !psHu8(DMAC_ENABLER+2)) { func(); ret = true; } return ret; }
__fi bool ReadFifoSingleWord() { u32 ptag[4]; //SIF_LOG(" EE SIF doing transfer %04Xqw to %08X", readSize, sif2dma.madr); SIF_LOG("Read Fifo SIF2 Single Word IOP Busy %x Fifo Size %x SIF2 CHCR %x", sif2.iop.busy, sif2.fifo.size, HW_DMA2_CHCR); sif2.fifo.read((u32*)&ptag[0], 1); psHu32(0x1000f3e0) = ptag[0]; if (sif2.fifo.size == 0) psxHu32(0x1000f300) |= 0x4000000; if (sif2.iop.busy && sif2.fifo.size <= 8)SIF2Dma(); return true; }
__fi u32 dmacRead32( u32 mem ) { // Fixme: OPH hack. Toggle the flag on GIF_STAT access. (rama) if (IsPageFor(mem) && (mem == GIF_STAT) && CHECK_OPHFLAGHACK) { static unsigned counter = 1; if (++counter == 8) counter = 2; // Set OPH and APATH from counter, cycling paths and alternating OPH return gifRegs.stat._u32 & ~(7 << 9) | (counter & 1 ? counter << 9 : 0); } return psHu32(mem); }
void __fastcall ReadFIFO_page_5(u32 mem, u64 *out) { jASSUME( (mem >= 0x10005000) && (mem < 0x10006000) ); VIF_LOG("ReadFIFO/VIF1, addr=0x%08X\n", mem); if( vif1Regs->stat & (VIF1_STAT_INT|VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS) ) DevCon::Notice( "Reading from vif1 fifo when stalled" ); if (vif1Regs->stat & 0x800000) { if (--psHu32(D1_QWC) == 0) vif1Regs->stat&= ~0x1f000000; } //out[0] = psHu64(mem ); //out[1] = psHu64(mem+8); out[0] = psHu64(0x5000); out[1] = psHu64(0x5008); }
static __ri void DmaExec( void (*func)(), u32 mem, u32 value ) { DMACh& reg = (DMACh&)psHu32(mem); tDMA_CHCR chcr(value); //It's invalid for the hardware to write a DMA while it is active, not without Suspending the DMAC if (reg.chcr.STR) { const uint channel = ChannelNumber(mem); if(psHu8(DMAC_ENABLER+2) == 1) //DMA is suspended so we can allow writes to anything { //If it stops the DMA, we need to clear any pending interrupts so the DMA doesnt continue. if(chcr.STR == 0) { //DevCon.Warning(L"32bit %s DMA Stopped on Suspend", ChcrName(mem)); if(channel == 1) { cpuClearInt( 10 ); QueuedDMA._u16 &= ~(1 << 10); //Clear any queued DMA requests for this channel } else if(channel == 2) { cpuClearInt( 11 ); QueuedDMA._u16 &= ~(1 << 11); //Clear any queued DMA requests for this channel } cpuClearInt( channel ); QueuedDMA._u16 &= ~(1 << channel); //Clear any queued DMA requests for this channel } //Sanity Check for possible future bug fix0rs ;p //Spams on Persona 4 opening. //if(reg.chcr.TAG != chcr.TAG) DevCon.Warning(L"32bit CHCR Tag on %s changed to %x from %x QWC = %x Channel Active", ChcrName(mem), chcr.TAG, reg.chcr.TAG, reg.qwc); //Here we update the LOWER CHCR, if a chain is stopped half way through, it can be manipulated in to a different mode //But we need to preserve the existing tag for now reg.chcr.set((reg.chcr.TAG << 16) | chcr.lower()); return; } else //Else the DMA is running (Not Suspended), so we cant touch it! { //As the manual states "Fields other than STR can only be written to when the DMA is stopped" //Also "The DMA may not stop properly just by writing 0 to STR" //So the presumption is that STR can be written to (ala force stop the DMA) but nothing else if(chcr.STR == 0) { //DevCon.Warning(L"32bit Force Stopping %s (Current CHCR %x) while DMA active", ChcrName(mem), reg.chcr._u32, chcr._u32); reg.chcr.STR = 0; //We need to clear any existing DMA loops that are in progress else they will continue! if(channel == 1) { cpuClearInt( 10 ); QueuedDMA._u16 &= ~(1 << 10); //Clear any queued DMA requests for this channel } else if(channel == 2) { cpuClearInt( 11 ); QueuedDMA._u16 &= ~(1 << 11); //Clear any queued DMA requests for this channel } cpuClearInt( channel ); QueuedDMA._u16 &= ~(1 << channel); //Clear any queued DMA requests for this channel } //else DevCon.Warning(L"32bit Attempted to change %s CHCR (Currently %x) with %x while DMA active, ignoring QWC = %x", ChcrName(mem), reg.chcr._u32, chcr._u32, reg.qwc); return; } } //if(reg.chcr.TAG != chcr.TAG && chcr.MOD == CHAIN_MODE) DevCon.Warning(L"32bit CHCR Tag on %s changed to %x from %x QWC = %x Channel Not Active", ChcrName(mem), chcr.TAG, reg.chcr.TAG, reg.qwc); reg.chcr.set(value); if (reg.chcr.STR && dmacRegs.ctrl.DMAE && !psHu8(DMAC_ENABLER+2)) { func(); } else if(reg.chcr.STR) { //DevCon.Warning(L"32bit %s DMA Start while DMAC Disabled\n", ChcrName(mem)); QueuedDMA._u16 |= (1 << ChannelNumber(mem)); //Queue the DMA up to be started then the DMA's are Enabled and or the Suspend is lifted } //else QueuedDMA._u16 &~= (1 << ChannelNumber(mem)); // }
static __ri void DmaExec( void (*func)(), u32 mem, u32 value ) { DMACh& reg = (DMACh&)psHu32(mem); tDMA_CHCR chcr(value); //It's invalid for the hardware to write a DMA while it is active, not without Suspending the DMAC if (reg.chcr.STR) { const uint channel = ChannelNumber(mem); //As the manual states "Fields other than STR can only be written to when the DMA is stopped" //Also "The DMA may not stop properly just by writing 0 to STR" //So the presumption is that STR can be written to (ala force stop the DMA) but nothing else //If the developer wishes to alter any of the other fields, it must be done AFTER the STR has been written, //it will not work before or during this event. if(chcr.STR == 0) { //DevCon.Warning(L"32bit Force Stopping %s (Current CHCR %x) while DMA active", ChcrName(mem), reg.chcr._u32, chcr._u32); reg.chcr.STR = 0; //We need to clear any existing DMA loops that are in progress else they will continue! if(channel == 1) { cpuClearInt( 10 ); QueuedDMA._u16 &= ~(1 << 10); //Clear any queued DMA requests for this channel } else if(channel == 2) { cpuClearInt( 11 ); QueuedDMA._u16 &= ~(1 << 11); //Clear any queued DMA requests for this channel } cpuClearInt( channel ); QueuedDMA._u16 &= ~(1 << channel); //Clear any queued DMA requests for this channel } //else DevCon.Warning(L"32bit Attempted to change %s CHCR (Currently %x) with %x while DMA active, ignoring QWC = %x", ChcrName(mem), reg.chcr._u32, chcr._u32, reg.qwc); return; } //if(reg.chcr.TAG != chcr.TAG && chcr.MOD == CHAIN_MODE) DevCon.Warning(L"32bit CHCR Tag on %s changed to %x from %x QWC = %x Channel Not Active", ChcrName(mem), chcr.TAG, reg.chcr.TAG, reg.qwc); reg.chcr.set(value); //Final Fantasy XII sets the DMA Mode to 3 which doesn't exist. On some channels (like SPR) this will break logic completely. so lets assume they mean chain. if (reg.chcr.MOD == 0x3) { static bool warned; //Check if the warning has already been output to console, to prevent constant spam. if (!warned) { DevCon.Warning(L"%s CHCR.MOD set to 3, assuming 1 (chain)", ChcrName(mem)); warned = true; } reg.chcr.MOD = 0x1; } if (reg.chcr.STR && dmacRegs.ctrl.DMAE && !psHu8(DMAC_ENABLER+2)) { func(); } else if(reg.chcr.STR) { //DevCon.Warning(L"32bit %s DMA Start while DMAC Disabled\n", ChcrName(mem)); QueuedDMA._u16 |= (1 << ChannelNumber(mem)); //Queue the DMA up to be started then the DMA's are Enabled and or the Suspend is lifted } //else QueuedDMA._u16 &~= (1 << ChannelNumber(mem)); // }