static u16 QWCinVIFMFIFO(u32 DrainADDR) { u32 ret; SPR_LOG("VIF MFIFO Requesting %x QWC from the MFIFO Base %x MFIFO Top %x, SPR MADR %x Drain %x", vif1ch.qwc, dmacRegs.rbor.ADDR, dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16, spr0ch.madr, DrainADDR); //Calculate what we have in the fifo. if(DrainADDR <= spr0ch.madr) { //Drain is below the tadr, calculate the difference between them ret = (spr0ch.madr - DrainADDR) >> 4; }
void SPRTOinterrupt() { SPR_LOG("SPR1 Interrupt"); if (!spr1finished || spr1ch.qwc > 0) { _dmaSPR1(); return; } DMA_LOG("SPR1 DMA End"); spr1ch.chcr.STR = false; spr1lastqwc = false; hwDmacIrq(DMAC_TO_SPR); }
void dmaSPR0() // fromSPR { SPR_LOG("dmaSPR0 chcr = %lx, madr = %lx, qwc = %lx, sadr = %lx", spr0ch.chcr._u32, spr0ch.madr, spr0ch.qwc, spr0ch.sadr); spr0finished = false; //Init if(spr0ch.chcr.MOD == CHAIN_MODE && spr0ch.qwc > 0) { //DevCon.Warning(L"SPR0 QWC on Chain " + spr0ch.chcr.desc()); if (spr0ch.chcr.tag().ID == TAG_END) // but not TAG_REFE? { // Correct not REFE, Destination Chain doesnt have REFE! spr0finished = true; } } SPRFROMinterrupt(); }
void dmaSPR1() // toSPR { SPR_LOG("dmaSPR1 chcr = 0x%x, madr = 0x%x, qwc = 0x%x\n" " tadr = 0x%x, sadr = 0x%x", spr1ch.chcr._u32, spr1ch.madr, spr1ch.qwc, spr1ch.tadr, spr1ch.sadr); spr1finished = false; //Init if(spr1ch.chcr.MOD == CHAIN_MODE && spr1ch.qwc > 0) { //DevCon.Warning(L"SPR1 QWC on Chain " + spr1ch.chcr.desc()); if ((spr1ch.chcr.tag().ID == TAG_END) || (spr1ch.chcr.tag().ID == TAG_REFE)) { spr1finished = true; } } SPRTOinterrupt(); }
void _SPR0interleave() { int qwc = spr0ch.qwc; int sqwc = dmacRegs.sqwc.SQWC; int tqwc = dmacRegs.sqwc.TQWC; tDMA_TAG *pMem; if (tqwc == 0) tqwc = qwc; //Console.WriteLn("dmaSPR0 interleave"); SPR_LOG("SPR0 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx", spr0ch.qwc, tqwc, sqwc, spr0ch.madr, spr0ch.sadr); CPU_INT(DMAC_FROM_SPR, qwc * BIAS); while (qwc > 0) { spr0ch.qwc = std::min(tqwc, qwc); qwc -= spr0ch.qwc; pMem = SPRdmaGetAddr(spr0ch.madr, true); switch (dmacRegs.ctrl.MFD) { case MFD_VIF1: case MFD_GIF: hwMFIFOWrite(spr0ch.madr, &psSu128(spr0ch.sadr), spr0ch.qwc); mfifotransferred += spr0ch.qwc; break; case NO_MFD: case MFD_RESERVED: // clear VU mem also! TestClearVUs(spr0ch.madr, spr0ch.qwc); memcpy_qwc(pMem, &psSu128(spr0ch.sadr), spr0ch.qwc); break; } spr0ch.sadr += spr0ch.qwc * 16; spr0ch.madr += (sqwc + spr0ch.qwc) * 16; } spr0ch.qwc = 0; }
void _SPR1interleave() { int qwc = spr1ch.qwc; int sqwc = dmacRegs.sqwc.SQWC; int tqwc = dmacRegs.sqwc.TQWC; tDMA_TAG *pMem; if (tqwc == 0) tqwc = qwc; SPR_LOG("SPR1 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx", spr1ch.qwc, tqwc, sqwc, spr1ch.madr, spr1ch.sadr); CPU_INT(DMAC_TO_SPR, qwc * BIAS); while (qwc > 0) { spr1ch.qwc = std::min(tqwc, qwc); qwc -= spr1ch.qwc; pMem = SPRdmaGetAddr(spr1ch.madr, false); memcpy_qwc(&psSu128(spr1ch.sadr), pMem, spr1ch.qwc); spr1ch.sadr += spr1ch.qwc * 16; spr1ch.madr += (sqwc + spr1ch.qwc) * 16; } spr1ch.qwc = 0; }
void _dmaSPR1() // toSPR work function { switch(spr1ch.chcr.MOD) { case NORMAL_MODE: { //int cycles = 0; // Transfer Dn_QWC from Dn_MADR to SPR1 SPR1chain(); spr1finished = true; return; } case CHAIN_MODE: { tDMA_TAG *ptag; bool done = false; if (spr1ch.qwc > 0) { SPR_LOG("spr1 Normal or in Progress size=%d, addr=%lx taddr=%lx saddr=%lx", spr1ch.qwc, spr1ch.madr, spr1ch.tadr, spr1ch.sadr); // Transfer Dn_QWC from Dn_MADR to SPR1 SPR1chain(); return; } // Chain Mode ptag = SPRdmaGetAddr(spr1ch.tadr, false); //Set memory pointer to TADR if (!spr1ch.transfer("SPR1 Tag", ptag)) { done = true; spr1finished = done; } spr1ch.madr = ptag[1]._u32; //MADR = ADDR field + SPR // Transfer dma tag if tte is set if (spr1ch.chcr.TTE) { SPR_LOG("SPR TTE: %x_%x\n", ptag[3]._u32, ptag[2]._u32); SPR1transfer(ptag, 1); //Transfer Tag } SPR_LOG("spr1 dmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx taddr=%lx saddr=%lx", ptag[1]._u32, ptag[0]._u32, spr1ch.qwc, ptag->ID, spr1ch.madr, spr1ch.tadr, spr1ch.sadr); done = (hwDmacSrcChain(spr1ch, ptag->ID)); SPR1chain(); //Transfers the data set by the switch if (spr1ch.chcr.TIE && ptag->IRQ) //Check TIE bit of CHCR and IRQ bit of tag { SPR_LOG("dmaIrq Set"); //Console.WriteLn("SPR1 TIE"); done = true; } spr1finished = done; break; } //case INTERLEAVE_MODE: default: { _SPR1interleave(); spr1finished = true; break; } } }
static __fi void _dmaSPR0() { if (dmacRegs.ctrl.STS == STS_fromSPR) { DevCon.Warning("SPR0 stall %d", dmacRegs.ctrl.STS); } // Transfer Dn_QWC from SPR to Dn_MADR switch(spr0ch.chcr.MOD) { case NORMAL_MODE: { SPR0chain(); spr0finished = true; return; } case CHAIN_MODE: { tDMA_TAG *ptag; bool done = false; if (spr0ch.qwc > 0) { SPR0chain(); return; } // Destination Chain Mode ptag = (tDMA_TAG*)&psSu32(spr0ch.sadr); spr0ch.sadr += 16; spr0ch.unsafeTransfer(ptag); spr0ch.madr = ptag[1]._u32; //MADR = ADDR field + SPR SPR_LOG("spr0 dmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx spr=%lx", ptag[1]._u32, ptag[0]._u32, spr0ch.qwc, ptag->ID, spr0ch.madr, spr0ch.sadr); if (dmacRegs.ctrl.STS == STS_fromSPR) // STS == fromSPR { Console.WriteLn("SPR stall control"); } switch (ptag->ID) { case TAG_CNTS: // CNTS - Transfer QWC following the tag (Stall Control) if (dmacRegs.ctrl.STS == STS_fromSPR) dmacRegs.stadr.ADDR = spr0ch.madr + (spr0ch.qwc * 16); //Copy MADR to DMAC_STADR stall addr register break; case TAG_CNT: // CNT - Transfer QWC following the tag. done = false; break; case TAG_END: // End - Transfer QWC following the tag done = true; break; } SPR0chain(); if (spr0ch.chcr.TIE && ptag->IRQ) //Check TIE bit of CHCR and IRQ bit of tag { //Console.WriteLn("SPR0 TIE"); done = true; } spr0finished = done; SPR_LOG("spr0 dmaChain complete %8.8x_%8.8x size=%d, id=%d, addr=%lx spr=%lx", ptag[1]._u32, ptag[0]._u32, spr0ch.qwc, ptag->ID, spr0ch.madr); break; } //case INTERLEAVE_MODE: default: { _SPR0interleave(); spr0finished = true; break; } } }