/* Pcsx2 - Pc Ps2 Emulator * Copyright (C) 2002-2003 Pcsx2 Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include "Common.h" #include "SPR.h" #include "ir5900.h" #define spr0 ((DMACh*)&PS2MEM_HW[0xD000]) #define spr1 ((DMACh*)&PS2MEM_HW[0xD400]) void sprInit() { } //__inline static void SPR0transfer(u32 *data, int size) { ///* while (size > 0) { //#ifdef SPR_LOG // SPR_LOG("SPR1transfer: %x\n", *data); //#endif // data++; size--; // }*/ // size <<= 2; // if ((psHu32(DMAC_CTRL) & 0xC) == 0xC || // GIF MFIFO // (psHu32(DMAC_CTRL) & 0xC) == 0x8) { // VIF1 MFIFO // hwMFIFOWrite(spr0->madr, (u8*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff], size); // } else { // u32 * p = (u32*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff]; // //WriteCodeSSE2(p,data,size >> 4); // memcpy_amd((u8*)data, &PS2MEM_SCRATCH[spr0->sadr & 0x3fff], size); // } // spr0->sadr+= size; //} static void TestClearVUs(u32 madr, u32 size) { if( madr >= 0x11000000 ) { if( madr < 0x11004000 ) { #ifdef _DEBUG SysPrintf("scratch pad clearing vu0\n"); #endif Cpu->ClearVU0(madr&0xfff, size); } else if( madr >= 0x11008000 && madr < 0x1100c000 ) { #ifdef _DEBUG SysPrintf("scratch pad clearing vu1\n"); #endif Cpu->ClearVU1(madr&0x3fff, size); } } } int _SPR0chain() { u32 qwc = spr0->qwc; u32 *pMem; if (qwc == 0) return 0; pMem = (u32*)dmaGetAddr(spr0->madr); if (pMem == NULL) return -1; //SPR0transfer(pMem, qwc << 2); qwc <<= 4; if ((psHu32(DMAC_CTRL) & 0xC) == 0xC || // GIF MFIFO (psHu32(DMAC_CTRL) & 0xC) == 0x8) { // VIF1 MFIFO hwMFIFOWrite(spr0->madr, (u8*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff], qwc); spr0->madr = psHu32(DMAC_RBOR) + ((spr0->madr + qwc) & (psHu32(DMAC_RBSR))); //Wrap MADR } else { Cpu->Clear(spr0->madr, qwc>>2); // clear VU mem also! TestClearVUs(spr0->madr, qwc>>2); memcpy_amd((u8*)pMem, &PS2MEM_SCRATCH[spr0->sadr & 0x3fff], qwc); spr0->madr += qwc; } spr0->sadr += qwc; spr0->qwc = 0; return (qwc>>4) * BIAS; // bus is 1/2 the ee speed } #define SPR0chain() \ if (spr0->qwc) { \ cycles += _SPR0chain(); \ /* cycles+= spr0->qwc / BIAS;*/ /* guessing */ \ } void _SPR0interleave() { int qwc = spr0->qwc; int sqwc = psHu32(DMAC_SQWC) & 0xff; int tqwc = (psHu32(DMAC_SQWC) >> 16) & 0xff; int cycles = 0; u32 *pMem; //SysPrintf("dmaSPR0 interleave\n"); while (qwc > 0) { spr0->qwc = min(tqwc, qwc); qwc-= spr0->qwc; pMem = (u32*)dmaGetAddr(spr0->madr); if ((psHu32(DMAC_CTRL) & 0xC) == 0xC || // GIF MFIFO (psHu32(DMAC_CTRL) & 0xC) == 0x8) { // VIF1 MFIFO hwMFIFOWrite(spr0->madr, (u8*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff], spr0->qwc<<4); } else { Cpu->Clear(spr0->madr, spr0->qwc<<2); // clear VU mem also! TestClearVUs(spr0->madr, qwc>>2); memcpy_amd((u8*)pMem, &PS2MEM_SCRATCH[spr0->sadr & 0x3fff], spr0->qwc<<4); } cycles += tqwc * BIAS; spr0->sadr+= spr0->qwc * 16; spr0->madr+= (sqwc+spr0->qwc)*16; //qwc-= sqwc; } spr0->qwc = 0; INT(8, cycles); } void _dmaSPR0() { u32 *ptag; int id; int cycles = 0; int done = 0; if ((psHu32(DMAC_CTRL) & 0x30) == 0x20) { // STS == fromSPR SysPrintf("SPR0 stall %d\n", (psHu32(DMAC_CTRL)>>6)&3); } if ((spr0->chcr & 0xc) == 0x8) { // Interleave Mode _SPR0interleave(); return; } // Transfer Dn_QWC from SPR to Dn_MADR SPR0chain(); if ((spr0->chcr & 0xc) == 0) { // Normal Mode INT(8, cycles); return; } // Destination Chain Mode while (done == 0) { // Loop while Dn_CHCR.STR is 1 ptag = (u32*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff]; spr0->sadr+= 16; // Transfer dma tag if tte is set // if (spr0->chcr & 0x40) SPR0transfer(ptag, 4); spr0->chcr = ( spr0->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 id = (ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag spr0->qwc = (u16)ptag[0]; //QWC set to lower 16bits of the tag spr0->madr = ptag[1]; //MADR = ADDR field #ifdef SPR_LOG SPR_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx\n", ptag[1], ptag[0], spr0->qwc, id, spr0->madr); #endif if ((psHu32(DMAC_CTRL) & 0x30) == 0x20) { // STS == fromSPR SysPrintf("SPR stall control\n"); } switch (id) { case 0: // CNTS - Transfer QWC following the tag (Stall Control) if ((psHu32(DMAC_CTRL) & 0x30) == 0x20 ) psHu32(DMAC_STADR) = spr0->madr; //Copy MADR to DMAC_STADR stall addr register break; case 1: // CNT - Transfer QWC following the tag. break; case 7: // End - Transfer QWC following the tag done = 1; //End Transfer break; } SPR0chain(); if (spr0->chcr & 0x80 && ptag[0] >> 31) { //Check TIE bit of CHCR and IRQ bit of tag //SysPrintf("SPR0 TIE\n"); done = 1; spr0->qwc = 0; break; } /* if (spr0->chcr & 0x80 && ptag[0] >> 31) { #ifdef SPR_LOG SPR_LOG("dmaIrq Set\n"); #endif spr0->chcr&= ~0x100; hwDmacIrq(8); return; }*/ } INT(8, cycles); } int SPRFROMinterrupt() { spr0->chcr&= ~0x100; hwDmacIrq(8); return 1; } void dmaSPR0() { // fromSPR int qwc = spr0->qwc; #ifdef SPR_LOG SPR_LOG("dmaSPR0 chcr = %lx, madr = %lx, qwc = %lx, sadr = %lx\n", spr0->chcr, spr0->madr, spr0->qwc, spr0->sadr); #endif _dmaSPR0(); if ((psHu32(DMAC_CTRL) & 0xC) == 0xC) { // GIF MFIFO spr0->madr = psHu32(DMAC_RBOR) + (spr0->madr & (psHu32(DMAC_RBSR))); mfifoGIFtransfer(qwc); } else if ((psHu32(DMAC_CTRL) & 0xC) == 0x8) { // VIF1 MFIFO spr0->madr = psHu32(DMAC_RBOR) + (spr0->madr & (psHu32(DMAC_RBSR))); mfifoVIF1transfer(qwc); } FreezeMMXRegs(0); FreezeXMMRegs(0); } __inline static void SPR1transfer(u32 *data, int size) { /* { int i; for (i=0; isadr+i*4) & 0x3fff, data[i] ); #endif } }*/ //Cpu->Clear(spr1->sadr, size); // why? memcpy_amd(&PS2MEM_SCRATCH[spr1->sadr & 0x3fff], (u8*)data, size << 2); spr1->sadr+= size << 2; } int _SPR1chain() { u32 qwc = spr1->qwc; u32 *pMem; if (qwc == 0) return 0; pMem = (u32*)dmaGetAddr(spr1->madr); if (pMem == NULL) return -1; SPR1transfer(pMem, qwc << 2); spr1->madr+= spr1->qwc << 4; spr1->qwc = 0; return (qwc) * BIAS; } #define SPR1chain() \ if (spr1->qwc) { \ cycles += _SPR1chain(); \ /* cycles+= spr1->qwc / BIAS;*/ /* guessing */ \ } void _SPR1interleave() { int qwc = spr1->qwc; int sqwc = psHu32(DMAC_SQWC) & 0xff; int tqwc = (psHu32(DMAC_SQWC) >> 16) & 0xff; int cycles = 0; u32 *pMem; //SysPrintf("dmaSPR1 interleave\n"); while (qwc > 0) { spr1->qwc = min(tqwc, qwc); qwc-= spr1->qwc; pMem = (u32*)dmaGetAddr(spr1->madr); SPR1transfer(pMem, spr1->qwc << 2); cycles += spr1->qwc * BIAS; spr1->madr+= (sqwc + spr1->qwc) * 16; //qwc-= sqwc; } spr1->qwc = 0; INT(9, cycles); } void dmaSPR1() { // toSPR u32 *ptag; int id, done=0; int cycles = 0; #ifdef SPR_LOG SPR_LOG("dmaSPR1 chcr = 0x%x, madr = 0x%x, qwc = 0x%x\n" " tadr = 0x%x, sadr = 0x%x\n", spr1->chcr, spr1->madr, spr1->qwc, spr1->tadr, spr1->sadr); #endif if ((spr1->chcr & 0xc) == 0x8) { // Interleave Mode _SPR1interleave(); FreezeMMXRegs(0); return; } // Transfer Dn_QWC from Dn_MADR to SPR1 SPR1chain(); if ((spr1->chcr & 0xc) == 0) { // Normal Mode INT(9, cycles); FreezeMMXRegs(0); return; } // Chain Mode while (done == 0) { // Loop while Dn_CHCR.STR is 1 ptag = (u32*)dmaGetAddr(spr1->tadr); //Set memory pointer to TADR if (ptag == NULL) { //Is ptag empty? psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register break; } // Transfer dma tag if tte is set if (spr1->chcr & 0x40) { #ifdef SPR_LOG SPR_LOG("SPR TTE: %x_%x\n", ptag[3], ptag[2]); #endif SPR1transfer(ptag, 4); //Transfer Tag } spr1->chcr = ( spr1->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 id = (ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag spr1->qwc = (u16)ptag[0]; //QWC set to lower 16bits of the tag spr1->madr = ptag[1]; //MADR = ADDR field #ifdef SPR_LOG SPR_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx\n", ptag[1], ptag[0], spr1->qwc, id, spr1->madr); #endif done = hwDmacSrcChain(spr1, id); SPR1chain(); //Transfers the data set by the switch if (spr1->chcr & 0x80 && ptag[0] >> 31) { //Check TIE bit of CHCR and IRQ bit of tag #ifdef SPR_LOG SPR_LOG("dmaIrq Set\n"); #endif //SysPrintf("SPR1 TIE\n"); spr1->qwc = 0; break; } } INT(9, cycles); FreezeMMXRegs(0); } int SPRTOinterrupt() { spr1->chcr &= ~0x100; hwDmacIrq(9); return 1; }