int _SPR0chain() { tDMA_TAG *pMem; int partialqwc = 0; if (spr0ch.qwc == 0) return 0; pMem = SPRdmaGetAddr(spr0ch.madr, true); if (pMem == NULL) return -1; switch (dmacRegs.ctrl.MFD) { case MFD_VIF1: case MFD_GIF: partialqwc = spr0ch.qwc; if ((spr0ch.madr & ~dmacRegs.rbsr.RMSK) != dmacRegs.rbor.ADDR) Console.WriteLn("SPR MFIFO Write outside MFIFO area"); else mfifotransferred += partialqwc; hwMFIFOWrite(spr0ch.madr, &psSu128(spr0ch.sadr), partialqwc); spr0ch.madr += partialqwc << 4; spr0ch.madr = dmacRegs.rbor.ADDR + (spr0ch.madr & dmacRegs.rbsr.RMSK); spr0ch.sadr += partialqwc << 4; spr0ch.qwc -= partialqwc; break; case NO_MFD: case MFD_RESERVED: //Taking an arbitary small value for games which like to check the QWC/MADR instead of STR, so get most of //the cycle delay out of the way before the end. partialqwc = spr0ch.qwc; memcpy_qwc(pMem, &psSu128(spr0ch.sadr), partialqwc); // clear VU mem also! TestClearVUs(spr0ch.madr, partialqwc << 2); // Wtf is going on here? AFAIK, only VIF should affect VU micromem (cottonvibes) spr0ch.madr += partialqwc << 4; spr0ch.sadr += partialqwc << 4; spr0ch.qwc -= partialqwc; break; } return (partialqwc); // bus is 1/2 the ee speed }
int _SPR0chain() { tDMA_TAG *pMem; int partialqwc = 0; if (spr0ch.qwc == 0) return 0; pMem = SPRdmaGetAddr(spr0ch.madr, true); if (pMem == NULL) return -1; if(spr0ch.madr >= dmacRegs.rbor.ADDR && spr0ch.madr < (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) { partialqwc = spr0ch.qwc; if ((spr0ch.madr & ~dmacRegs.rbsr.RMSK) != dmacRegs.rbor.ADDR) Console.WriteLn("SPR MFIFO Write outside MFIFO area"); else mfifotransferred += partialqwc; hwMFIFOWrite(spr0ch.madr, &psSu128(spr0ch.sadr), partialqwc); spr0ch.madr += partialqwc << 4; spr0ch.madr = dmacRegs.rbor.ADDR + (spr0ch.madr & dmacRegs.rbsr.RMSK); spr0ch.sadr += partialqwc << 4; spr0ch.qwc -= partialqwc; spr0finished = true; } else { //Taking an arbitary small value for games which like to check the QWC/MADR instead of STR, so get most of //the cycle delay out of the way before the end. partialqwc = spr0ch.qwc; memcpy_qwc(pMem, &psSu128(spr0ch.sadr), partialqwc); // clear VU mem also! TestClearVUs(spr0ch.madr, partialqwc); spr0ch.madr += partialqwc << 4; spr0ch.sadr += partialqwc << 4; spr0ch.qwc -= partialqwc; } return (partialqwc); // bus is 1/2 the ee speed }
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; }
int _SPR1chain() { tDMA_TAG *pMem; if (spr1ch.qwc == 0) return 0; pMem = SPRdmaGetAddr(spr1ch.madr, false); if (pMem == NULL) return -1; int partialqwc = 0; //Taking an arbitary small value for games which like to check the QWC/MADR instead of STR, so get most of //the cycle delay out of the way before the end. partialqwc = spr1ch.qwc; SPR1transfer(pMem, partialqwc); spr1ch.madr += partialqwc * 16; spr1ch.qwc -= partialqwc; hwDmacSrcTadrInc(spr1ch); return (partialqwc); }
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; } } }