Clang: Format Gif.cpp, Vif_Codes.cpp, Vif.cpp

This commit is contained in:
refractionpcsx2 2021-07-29 10:42:03 +01:00
parent 88edd1acd6
commit 88a53f013e
3 changed files with 550 additions and 308 deletions

View File

@ -29,38 +29,48 @@
__aligned16 GIF_Fifo gif_fifo;
__aligned16 gifStruct gif;
static __fi void GifDMAInt(int cycles) {
if (dmacRegs.ctrl.MFD == MFD_GIF) {
static __fi void GifDMAInt(int cycles)
{
if (dmacRegs.ctrl.MFD == MFD_GIF)
{
if (!(cpuRegs.interrupt & (1 << DMAC_MFIFO_GIF)) || cpuRegs.eCycle[DMAC_MFIFO_GIF] < (u32)cycles)
{
CPU_INT(DMAC_MFIFO_GIF, cycles);
}
} else if (!(cpuRegs.interrupt & (1 << DMAC_GIF)) || cpuRegs.eCycle[DMAC_GIF] < (u32)cycles)
}
else if (!(cpuRegs.interrupt & (1 << DMAC_GIF)) || cpuRegs.eCycle[DMAC_GIF] < (u32)cycles)
{
CPU_INT(DMAC_GIF, cycles);
}
}
__fi void clearFIFOstuff(bool full) {
CSRreg.FIFO = full ? CSR_FIFO_FULL : CSR_FIFO_EMPTY;
__fi void clearFIFOstuff(bool full)
{
CSRreg.FIFO = full ? CSR_FIFO_FULL : CSR_FIFO_EMPTY;
}
//I suspect this is GS side which should really be handled by GS which also doesn't current have a fifo, but we can guess from our fifo
static __fi void CalculateFIFOCSR() {
if (gifRegs.stat.FQC >= 15) {
static __fi void CalculateFIFOCSR()
{
if (gifRegs.stat.FQC >= 15)
{
CSRreg.FIFO = CSR_FIFO_FULL;
}
else if (gifRegs.stat.FQC == 0) {
else if (gifRegs.stat.FQC == 0)
{
CSRreg.FIFO = CSR_FIFO_EMPTY;
}
else {
else
{
CSRreg.FIFO = CSR_FIFO_NORMAL;
}
}
bool CheckPaths() {
bool CheckPaths()
{
// Can't do Path 3, so try dma again later...
if (!gifUnit.CanDoPath3()) {
if (!gifUnit.CanDoPath3())
{
if (!gifUnit.Path3Masked())
{
//DevCon.Warning("Path3 stalled APATH %x PSE %x DIR %x Signal %x", gifRegs.stat.APATH, gifRegs.stat.PSE, gifRegs.stat.DIR, gifUnit.gsSIGNAL.queued);
@ -83,13 +93,13 @@ void GIF_Fifo::init()
gif.gscycles = 0;
gif.prevcycles = 0;
gif.mfifocycles = 0;
}
int GIF_Fifo::write_fifo(u32* pMem, int size)
{
if (fifoSize == 16) {
if (fifoSize == 16)
{
//GIF_LOG("GIF FIFO Full");
return 0;
}
@ -130,7 +140,8 @@ int GIF_Fifo::read_fifo()
GIF_LOG("GIF FIFO Read %d QW from FIFO Current Size %d", sizeRead, fifoSize);
if (sizeRead < fifoSize) {
if (sizeRead < fifoSize)
{
if (sizeRead > 0)
{
int copyAmount = fifoSize - sizeRead;
@ -160,16 +171,20 @@ int GIF_Fifo::read_fifo()
return sizeRead;
}
void incGifChAddr(u32 qwc) {
if (gifch.chcr.STR) {
void incGifChAddr(u32 qwc)
{
if (gifch.chcr.STR)
{
gifch.madr += qwc * 16;
gifch.qwc -= qwc;
gifch.qwc -= qwc;
hwDmacSrcTadrInc(gifch);
}
else DevCon.Error("incGifAddr() Error!");
else
DevCon.Error("incGifAddr() Error!");
}
__fi void gifCheckPathStatus() {
__fi void gifCheckPathStatus()
{
if (gifRegs.stat.APATH == 3)
{
@ -177,7 +192,8 @@ __fi void gifCheckPathStatus() {
gifRegs.stat.OPH = 0;
if (gifUnit.gifPath[GIF_PATH_3].state == GIF_PATH_IDLE || gifUnit.gifPath[GIF_PATH_3].state == GIF_PATH_WAIT)
{
if (gifUnit.checkPaths(1, 1, 0)) gifUnit.Execute(false, true);
if (gifUnit.checkPaths(1, 1, 0))
gifUnit.Execute(false, true);
}
}
@ -191,34 +207,37 @@ __fi void gifInterrupt()
GIF_LOG("gifInterrupt caught qwc=%d fifo=%d apath=%d oph=%d state=%d!", gifch.qwc, gifRegs.stat.FQC, gifRegs.stat.APATH, gifRegs.stat.OPH, gifUnit.gifPath[GIF_PATH_3].state);
gifCheckPathStatus();
if(gifUnit.gifPath[GIF_PATH_3].state == GIF_PATH_IDLE)
if (gifUnit.gifPath[GIF_PATH_3].state == GIF_PATH_IDLE)
{
if(vif1Regs.stat.VGW)
if (vif1Regs.stat.VGW)
{
// Check if VIF is in a cycle or is currently "idle" waiting for GIF to come back.
if(!(cpuRegs.interrupt & (1<<DMAC_VIF1)))
if (!(cpuRegs.interrupt & (1 << DMAC_VIF1)))
CPU_INT(DMAC_VIF1, 1);
// Make sure it loops if the GIF packet is empty to prepare for the next packet
// or end if it was the end of a packet.
// This must trigger after VIF retriggers as VIf might instantly mask Path3
if (!gifUnit.Path3Masked() || gifch.qwc == 0) {
if (!gifUnit.Path3Masked() || gifch.qwc == 0)
{
GifDMAInt(16);
}
return;
}
}
if (dmacRegs.ctrl.MFD == MFD_GIF) { // GIF MFIFO
if (dmacRegs.ctrl.MFD == MFD_GIF)
{ // GIF MFIFO
//Console.WriteLn("GIF MFIFO");
gifMFIFOInterrupt();
return;
}
if (gifUnit.gsSIGNAL.queued) {
if (gifUnit.gsSIGNAL.queued)
{
GIF_LOG("Path 3 Paused");
GifDMAInt(128);
if(gif_fifo.fifoSize == 16)
if (gif_fifo.fifoSize == 16)
return;
}
@ -237,7 +256,8 @@ __fi void gifInterrupt()
if (vif1Regs.stat.VGW)
{
// Check if VIF is in a cycle or is currently "idle" waiting for GIF to come back.
if (!(cpuRegs.interrupt & (1 << DMAC_VIF1))) {
if (!(cpuRegs.interrupt & (1 << DMAC_VIF1)))
{
CPU_INT(DMAC_VIF1, 1);
}
}
@ -247,13 +267,16 @@ __fi void gifInterrupt()
return;
}
if (!(gifch.chcr.STR)) return;
if (!(gifch.chcr.STR))
return;
if ((gifch.qwc > 0) || (!gif.gspath3done)) {
if (!dmacRegs.ctrl.DMAE) {
if ((gifch.qwc > 0) || (!gif.gspath3done))
{
if (!dmacRegs.ctrl.DMAE)
{
Console.Warning("gs dma masked, re-scheduling...");
// Re-raise the int shortly in the future
GifDMAInt( 64 );
GifDMAInt(64);
return;
}
GIFdma();
@ -262,17 +285,18 @@ __fi void gifInterrupt()
}
gif.gscycles = 0;
gifch.chcr.STR = false;
gifch.chcr.STR = false;
gifRegs.stat.FQC = gif_fifo.fifoSize;
CalculateFIFOCSR();
hwDmacIrq(DMAC_GIF);
if(gif_fifo.fifoSize)
if (gif_fifo.fifoSize)
GifDMAInt(8 * BIAS);
GIF_LOG("GIF DMA End QWC in fifo %x APATH = %x OPH = %x state = %x", gifRegs.stat.FQC, gifRegs.stat.APATH, gifRegs.stat.OPH, gifUnit.gifPath[GIF_PATH_3].state);
}
static u32 WRITERING_DMA(u32 *pMem, u32 qwc) {
static u32 WRITERING_DMA(u32* pMem, u32 qwc)
{
u32 originalQwc = qwc;
if (gifRegs.stat.IMT)
@ -282,7 +306,7 @@ static u32 WRITERING_DMA(u32 *pMem, u32 qwc) {
// so we can get away with transferring "most" of it when it's a big packet.
// Use Wallace and Gromit Project Zoo or The Suffering for testing
if (qwc > 64)
qwc = qwc-64;
qwc = qwc - 64;
else
qwc = std::min(qwc, 8u);
}
@ -305,11 +329,13 @@ static u32 WRITERING_DMA(u32 *pMem, u32 qwc) {
return size;
}
static __fi void GIFchain() {
static __fi void GIFchain()
{
tDMA_TAG* pMem;
pMem = dmaGetAddr(gifch.madr, false);
if (pMem == NULL) {
if (pMem == NULL)
{
// Must increment madr and clear qwc, else it loops
gifch.madr += gifch.qwc * 16;
gifch.qwc = 0;
@ -317,16 +343,17 @@ static __fi void GIFchain() {
return;
}
int transferred= WRITERING_DMA((u32*)pMem, gifch.qwc);
int transferred = WRITERING_DMA((u32*)pMem, gifch.qwc);
gif.gscycles += transferred * BIAS;
if (!gifUnit.Path3Masked() || (gif_fifo.fifoSize < 16))
GifDMAInt(gif.gscycles);
}
static __fi bool checkTieBit(tDMA_TAG* &ptag)
static __fi bool checkTieBit(tDMA_TAG*& ptag)
{
if (gifch.chcr.TIE && ptag->IRQ) {
if (gifch.chcr.TIE && ptag->IRQ)
{
GIF_LOG("dmaIrq Set");
gif.gspath3done = true;
return true;
@ -336,12 +363,13 @@ static __fi bool checkTieBit(tDMA_TAG* &ptag)
static __fi tDMA_TAG* ReadTag()
{
tDMA_TAG* ptag = dmaGetAddr(gifch.tadr, false); // Set memory pointer to TADR
tDMA_TAG* ptag = dmaGetAddr(gifch.tadr, false); // Set memory pointer to TADR
if (!(gifch.transfer("Gif", ptag))) return NULL;
if (!(gifch.transfer("Gif", ptag)))
return NULL;
gifch.madr = ptag[1]._u32; // MADR = ADDR field + SPR
gif.gscycles += 2; // Add 1 cycles from the QW read for the tag
gifch.madr = ptag[1]._u32; // MADR = ADDR field + SPR
gif.gscycles += 2; // Add 1 cycles from the QW read for the tag
gif.gspath3done = hwDmacSrcChainWithStack(gifch, ptag->ID);
return ptag;
@ -349,7 +377,7 @@ static __fi tDMA_TAG* ReadTag()
static __fi tDMA_TAG* ReadTag2()
{
tDMA_TAG* ptag = dmaGetAddr(gifch.tadr, false); // Set memory pointer to TADR
tDMA_TAG* ptag = dmaGetAddr(gifch.tadr, false); // Set memory pointer to TADR
gifch.unsafeTransfer(ptag);
gifch.madr = ptag[1]._u32;
@ -360,19 +388,23 @@ static __fi tDMA_TAG* ReadTag2()
void GIFdma()
{
while (gifch.qwc > 0 || !gif.gspath3done) {
while (gifch.qwc > 0 || !gif.gspath3done)
{
tDMA_TAG* ptag;
gif.gscycles = gif.prevcycles;
if (gifRegs.ctrl.PSE) { // Temporarily stop
if (gifRegs.ctrl.PSE)
{ // Temporarily stop
Console.WriteLn("Gif dma temp paused? (non MFIFO GIF)");
GifDMAInt(16);
return;
}
if ((dmacRegs.ctrl.STD == STD_GIF) && (gif.prevcycles != 0)) {
if ((dmacRegs.ctrl.STD == STD_GIF) && (gif.prevcycles != 0))
{
//Console.WriteLn("GS Stall Control Source = %x, Drain = %x\n MADR = %x, STADR = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3, gifch.madr, psHu32(DMAC_STADR));
if ((gifch.madr + (gifch.qwc * 16)) > dmacRegs.stadr.ADDR) {
if ((gifch.madr + (gifch.qwc * 16)) > dmacRegs.stadr.ADDR)
{
GifDMAInt(4);
gif.gscycles = 0;
return;
@ -384,7 +416,8 @@ void GIFdma()
if ((gifch.chcr.MOD == CHAIN_MODE) && (!gif.gspath3done) && gifch.qwc == 0) // Chain Mode
{
ptag = ReadTag();
if (ptag == NULL) return;
if (ptag == NULL)
return;
//DevCon.Warning("GIF Reading Tag MSK = %x", vif1Regs.mskpath3);
GIF_LOG("gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx tadr=%lx", ptag[1]._u32, ptag[0]._u32, gifch.qwc, ptag->ID, gifch.madr, gifch.tadr);
gifRegs.stat.FQC = std::min((u32)0x10, gifch.qwc);
@ -418,7 +451,7 @@ void GIFdma()
// Transfer Dn_QWC from Dn_MADR to GIF
if (gifch.qwc > 0) // Normal Mode
{
GIFchain(); // Transfers the data set by the switch
GIFchain(); // Transfers the data set by the switch
return;
}
}
@ -433,13 +466,16 @@ void dmaGIF()
gif.gspath3done = false; // For some reason this doesn't clear? So when the system starts the thread, we will clear it :)
if (gifch.chcr.MOD == NORMAL_MODE) { // Else it really is a normal transfer and we want to quit, else it gets confused with chains
if (gifch.chcr.MOD == NORMAL_MODE)
{ // Else it really is a normal transfer and we want to quit, else it gets confused with chains
gif.gspath3done = true;
}
if(gifch.chcr.MOD == CHAIN_MODE && gifch.qwc > 0) {
if (gifch.chcr.MOD == CHAIN_MODE && gifch.qwc > 0)
{
//DevCon.Warning(L"GIF QWC on Chain " + gifch.chcr.desc());
if ((gifch.chcr.tag().ID == TAG_REFE) || (gifch.chcr.tag().ID == TAG_END) || (gifch.chcr.tag().IRQ && gifch.chcr.TIE)) {
if ((gifch.chcr.tag().ID == TAG_REFE) || (gifch.chcr.tag().ID == TAG_END) || (gifch.chcr.tag().IRQ && gifch.chcr.TIE))
{
gif.gspath3done = true;
}
}
@ -453,17 +489,19 @@ static u32 QWCinGIFMFIFO(u32 DrainADDR)
SPR_LOG("GIF MFIFO Requesting %x QWC from the MFIFO Base %x, SPR MADR %x Drain %x", gifch.qwc, dmacRegs.rbor.ADDR, spr0ch.madr, DrainADDR);
// Calculate what we have in the fifo.
if (DrainADDR <= spr0ch.madr) {
if (DrainADDR <= spr0ch.madr)
{
// Drain is below the write position, calculate the difference between them
ret = (spr0ch.madr - DrainADDR) >> 4;
}
else {
else
{
u32 limit = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16;
// Drain is higher than SPR so it has looped round,
// Drain is higher than SPR so it has looped round,
// calculate from base to the SPR tag addr and what is left in the top of the ring
ret = ((spr0ch.madr - dmacRegs.rbor.ADDR) + (limit - DrainADDR)) >> 4;
}
if (ret == 0)
if (ret == 0)
gif.gifstate = GIF_STATE_EMPTY;
SPR_LOG("%x Available of the %x requested", ret, gifch.qwc);
@ -478,7 +516,8 @@ static __fi bool mfifoGIFrbTransfer()
return true;
u8* src = (u8*)PSM(gifch.madr);
if (src == NULL) return false;
if (src == NULL)
return false;
u32 MFIFOUntilEnd = ((dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16) - gifch.madr) >> 4;
bool needWrap = MFIFOUntilEnd < qwc;
@ -497,7 +536,8 @@ static __fi bool mfifoGIFrbTransfer()
uint secondTransQWC = qwc - MFIFOUntilEnd;
src = (u8*)PSM(dmacRegs.rbor.ADDR);
if (src == NULL) return false;
if (src == NULL)
return false;
transferred2 = WRITERING_DMA((u32*)src, secondTransQWC); // Second part
@ -520,7 +560,8 @@ static __fi void mfifoGIFchain()
if ((gifch.madr & ~dmacRegs.rbsr.RMSK) == dmacRegs.rbor.ADDR)
{
if (QWCinGIFMFIFO(gifch.madr) == 0) {
if (QWCinGIFMFIFO(gifch.madr) == 0)
{
SPR_LOG("GIF FIFO EMPTY before transfer");
gif.gifstate = GIF_STATE_EMPTY;
gif.mfifocycles += 4;
@ -540,10 +581,11 @@ static __fi void mfifoGIFchain()
gifch.madr = dmacRegs.rbor.ADDR + (gifch.madr & dmacRegs.rbsr.RMSK);
gifch.tadr = gifch.madr;
}
else {
else
{
SPR_LOG("Non-MFIFO Location transfer doing %x Total QWC", gifch.qwc);
tDMA_TAG *pMem = dmaGetAddr(gifch.madr, false);
if (pMem == NULL)
tDMA_TAG* pMem = dmaGetAddr(gifch.madr, false);
if (pMem == NULL)
{
gif.mfifocycles += 4;
gifch.qwc = 0;
@ -557,27 +599,29 @@ static __fi void mfifoGIFchain()
return;
}
static u32 qwctag(u32 mask) {
static u32 qwctag(u32 mask)
{
return (dmacRegs.rbor.ADDR + (mask & dmacRegs.rbsr.RMSK));
}
void mfifoGifMaskMem(int id)
{
switch (id) {
switch (id)
{
// These five transfer data following the tag, need to check its within the buffer (Front Mission 4)
case TAG_CNT:
case TAG_NEXT:
case TAG_CALL:
case TAG_CALL:
case TAG_RET:
case TAG_END:
if(gifch.madr < dmacRegs.rbor.ADDR) // Probably not needed but we will check anyway.
if (gifch.madr < dmacRegs.rbor.ADDR) // Probably not needed but we will check anyway.
{
SPR_LOG("GIF MFIFO MADR below bottom of ring buffer, wrapping GIF MADR = %x Ring Bottom %x", gifch.madr, dmacRegs.rbor.ADDR);
gifch.madr = qwctag(gifch.madr);
} else
if(gifch.madr > (dmacRegs.rbor.ADDR + (u32)dmacRegs.rbsr.RMSK)) // Usual scenario is the tag is near the end (Front Mission 4)
}
else if (gifch.madr > (dmacRegs.rbor.ADDR + (u32)dmacRegs.rbsr.RMSK)) // Usual scenario is the tag is near the end (Front Mission 4)
{
SPR_LOG("GIF MFIFO MADR outside top of ring buffer, wrapping GIF MADR = %x Ring Top %x", gifch.madr, (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK)+16);
SPR_LOG("GIF MFIFO MADR outside top of ring buffer, wrapping GIF MADR = %x Ring Top %x", gifch.madr, (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK) + 16);
gifch.madr = qwctag(gifch.madr);
}
break;
@ -589,19 +633,22 @@ void mfifoGifMaskMem(int id)
void mfifoGIFtransfer()
{
tDMA_TAG *ptag;
tDMA_TAG* ptag;
gif.mfifocycles = 0;
if (gifRegs.ctrl.PSE) { // Temporarily stop
if (gifRegs.ctrl.PSE)
{ // Temporarily stop
Console.WriteLn("Gif dma temp paused?");
CPU_INT(DMAC_MFIFO_GIF, 16);
return;
}
if (gifch.qwc == 0) {
if (gifch.qwc == 0)
{
gifch.tadr = qwctag(gifch.tadr);
if (QWCinGIFMFIFO(gifch.tadr) == 0) {
if (QWCinGIFMFIFO(gifch.tadr) == 0)
{
SPR_LOG("GIF FIFO EMPTY before tag read");
gif.gifstate = GIF_STATE_EMPTY;
GifDMAInt(4);
@ -618,7 +665,7 @@ void mfifoGIFtransfer()
gif.mfifocycles += 2;
GIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx mfifo qwc = %x spr0 madr = %x",
ptag[1]._u32, ptag[0]._u32, gifch.qwc, ptag->ID, gifch.madr, gifch.tadr, gif.gifqwc, spr0ch.madr);
ptag[1]._u32, ptag[0]._u32, gifch.qwc, ptag->ID, gifch.madr, gifch.tadr, gif.gifqwc, spr0ch.madr);
gif.gspath3done = hwDmacSrcChainWithStack(gifch, ptag->ID);
@ -630,14 +677,15 @@ void mfifoGIFtransfer()
gifch.tadr = qwctag(gifch.tadr);
if ((gifch.chcr.TIE) && (ptag->IRQ)) {
if ((gifch.chcr.TIE) && (ptag->IRQ))
{
SPR_LOG("dmaIrq Set");
gif.gspath3done = true;
}
}
}
mfifoGIFchain();
GifDMAInt(std::max(gif.mfifocycles, (u32)4));
SPR_LOG("mfifoGIFtransfer end %x madr %x, tadr %x", gifch.chcr._u32, gifch.madr, gifch.tadr);
@ -648,7 +696,8 @@ void gifMFIFOInterrupt()
//DevCon.Warning("gifMFIFOInterrupt");
gif.mfifocycles = 0;
if (dmacRegs.ctrl.MFD != MFD_GIF) { // GIF not in MFIFO anymore, come out.
if (dmacRegs.ctrl.MFD != MFD_GIF)
{ // GIF not in MFIFO anymore, come out.
DevCon.WriteLn("GIF Leaving MFIFO - Report if any errors");
gifInterrupt();
return;
@ -667,14 +716,16 @@ void gifMFIFOInterrupt()
// Make sure it loops if the GIF packet is empty to prepare for the next packet
// or end if it was the end of a packet.
// This must trigger after VIF retriggers as VIf might instantly mask Path3
if (!gifUnit.Path3Masked() || gifch.qwc == 0) {
if (!gifUnit.Path3Masked() || gifch.qwc == 0)
{
GifDMAInt(16);
}
return;
}
}
if (gifUnit.gsSIGNAL.queued) {
if (gifUnit.gsSIGNAL.queued)
{
GifDMAInt(128);
return;
}
@ -692,7 +743,8 @@ void gifMFIFOInterrupt()
// Make sure it loops if the GIF packet is empty to prepare for the next packet
// or end if it was the end of a packet.
// This must trigger after VIF retriggers as VIf might instantly mask Path3
if (!gifUnit.Path3Masked() || gifch.qwc == 0) {
if (!gifUnit.Path3Masked() || gifch.qwc == 0)
{
GifDMAInt(16);
}
return;
@ -714,7 +766,8 @@ void gifMFIFOInterrupt()
if (vif1Regs.stat.VGW)
{
//Check if VIF is in a cycle or is currently "idle" waiting for GIF to come back.
if (!(cpuRegs.interrupt & (1 << DMAC_VIF1))) {
if (!(cpuRegs.interrupt & (1 << DMAC_VIF1)))
{
CPU_INT(DMAC_VIF1, 1);
}
}
@ -727,7 +780,8 @@ void gifMFIFOInterrupt()
if (!gifch.chcr.STR)
return;
if (spr0ch.madr == gifch.tadr || (gif.gifstate & GIF_STATE_EMPTY)) {
if (spr0ch.madr == gifch.tadr || (gif.gifstate & GIF_STATE_EMPTY))
{
gif.gifstate = GIF_STATE_EMPTY; // In case of madr = tadr we need to set it
FireMFIFOEmpty();
@ -735,14 +789,15 @@ void gifMFIFOInterrupt()
return;
}
if (gifch.qwc > 0 || !gif.gspath3done) {
if (gifch.qwc > 0 || !gif.gspath3done)
{
mfifoGIFtransfer();
return;
}
gif.gscycles = 0;
gifch.chcr.STR = false;
gif.gifstate = GIF_STATE_READY;
gifRegs.stat.FQC = gif_fifo.fifoSize;
@ -754,7 +809,8 @@ void gifMFIFOInterrupt()
DMA_LOG("GIF MFIFO DMA End");
}
void SaveStateBase::gifDmaFreeze() {
void SaveStateBase::gifDmaFreeze()
{
// Note: mfifocycles is not a persistent var, so no need to save it here.
FreezeTag("GIFdma");
Freeze(gif.gifstate);

View File

@ -23,7 +23,7 @@
#include "MTVU.h"
#include "Gif_Unit.h"
__aligned16 vifStruct vif0, vif1;
__aligned16 vifStruct vif0, vif1;
void vif0Reset()
{
@ -46,7 +46,7 @@ void vif1Reset()
void SaveStateBase::vif0Freeze()
{
FreezeTag("VIF0dma");
Freeze(g_vif0Cycles);
Freeze(vif0);
@ -58,7 +58,7 @@ void SaveStateBase::vif0Freeze()
void SaveStateBase::vif1Freeze()
{
FreezeTag("VIF1dma");
Freeze(g_vif1Cycles);
Freeze(vif1);
@ -71,7 +71,8 @@ void SaveStateBase::vif1Freeze()
// Vif0/Vif1 Write32
//------------------------------------------------------------------
__fi void vif0FBRST(u32 value) {
__fi void vif0FBRST(u32 value)
{
VIF_LOG("VIF0_FBRST write32 0x%8.8x", value);
if (value & 0x1) // Reset Vif.
@ -80,7 +81,7 @@ __fi void vif0FBRST(u32 value) {
u128 SaveCol;
u128 SaveRow;
// if(vif0ch.chcr.STR) DevCon.Warning("FBRST While Vif0 active");
// if(vif0ch.chcr.STR) DevCon.Warning("FBRST While Vif0 active");
//Must Preserve Row/Col registers! (Downhill Domination for testing)
SaveCol._u64[0] = vif0.MaskCol._u64[0];
SaveCol._u64[1] = vif0.MaskCol._u64[1];
@ -135,19 +136,21 @@ __fi void vif0FBRST(u32 value) {
cancel = true;
vif0Regs.stat.clear_flags(VIF0_STAT_VSS | VIF0_STAT_VFS | VIF0_STAT_VIS |
VIF0_STAT_INT | VIF0_STAT_ER0 | VIF0_STAT_ER1);
VIF0_STAT_INT | VIF0_STAT_ER0 | VIF0_STAT_ER1);
if (cancel)
{
g_vif0Cycles = 0;
// loop necessary for spiderman
if(vif0ch.chcr.STR) CPU_INT(DMAC_VIF0, 0); // Gets the timing right - Flatout
{
g_vif0Cycles = 0;
// loop necessary for spiderman
if (vif0ch.chcr.STR)
CPU_INT(DMAC_VIF0, 0); // Gets the timing right - Flatout
}
}
}
__fi void vif1FBRST(u32 value) {
__fi void vif1FBRST(u32 value)
{
VIF_LOG("VIF1_FBRST write32 0x%8.8x", value);
if (FBRST(value).RST) // Reset Vif.
{
u128 SaveCol;
@ -168,7 +171,7 @@ __fi void vif1FBRST(u32 value) {
GUNIT_WARN(Color_Red, "VIF FBRST Reset MSK = %x", vif1Regs.mskpath3);
vif1Regs.mskpath3 = false;
gifRegs.stat.M3P = 0;
gifRegs.stat.M3P = 0;
vif1Regs.err.reset();
vif1.inprogress = mfifo_empty;
vif1.cmd = 0;
@ -211,41 +214,46 @@ __fi void vif1FBRST(u32 value) {
}
vif1Regs.stat.clear_flags(VIF1_STAT_VSS | VIF1_STAT_VFS | VIF1_STAT_VIS |
VIF1_STAT_INT | VIF1_STAT_ER0 | VIF1_STAT_ER1);
VIF1_STAT_INT | VIF1_STAT_ER0 | VIF1_STAT_ER1);
if (cancel)
{
g_vif1Cycles = 0;
// loop necessary for spiderman
switch(dmacRegs.ctrl.MFD)
{
case MFD_VIF1:
//Console.WriteLn("MFIFO Stall");
//MFIFO active and not empty
if(vif1ch.chcr.STR && !vif1Regs.stat.test(VIF1_STAT_FDR)) CPU_INT(DMAC_MFIFO_VIF, 0);
break;
g_vif1Cycles = 0;
// loop necessary for spiderman
switch (dmacRegs.ctrl.MFD)
{
case MFD_VIF1:
//Console.WriteLn("MFIFO Stall");
//MFIFO active and not empty
if (vif1ch.chcr.STR && !vif1Regs.stat.test(VIF1_STAT_FDR))
CPU_INT(DMAC_MFIFO_VIF, 0);
break;
case NO_MFD:
case MFD_RESERVED:
case MFD_GIF: // Wonder if this should be with VIF?
// Gets the timing right - Flatout
if(vif1ch.chcr.STR && !vif1Regs.stat.test(VIF1_STAT_FDR)) CPU_INT(DMAC_VIF1, 0);
break;
}
case NO_MFD:
case MFD_RESERVED:
case MFD_GIF: // Wonder if this should be with VIF?
// Gets the timing right - Flatout
if (vif1ch.chcr.STR && !vif1Regs.stat.test(VIF1_STAT_FDR))
CPU_INT(DMAC_VIF1, 0);
break;
}
//vif1ch.chcr.STR = true;
//vif1ch.chcr.STR = true;
}
}
}
__fi void vif1STAT(u32 value) {
__fi void vif1STAT(u32 value)
{
VIF_LOG("VIF1_STAT write32 0x%8.8x", value);
/* Only FDR bit is writable, so mask the rest */
if ((vif1Regs.stat.FDR) ^ ((tVIF_STAT&)value).FDR) {
if ((vif1Regs.stat.FDR) ^ ((tVIF_STAT&)value).FDR)
{
bool isStalled = false;
// different so can't be stalled
if (vif1Regs.stat.test(VIF1_STAT_INT | VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS)) {
if (vif1Regs.stat.test(VIF1_STAT_INT | VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS))
{
DbgCon.WriteLn("changing dir when vif1 fifo stalled done = %x qwc = %x stat = %x", vif1.done, vif1ch.qwc, vif1Regs.stat._u32);
isStalled = true;
}
@ -255,7 +263,8 @@ __fi void vif1STAT(u32 value) {
//Hotwheels had this in the "direction when stalled" area, however Sled Storm seems to keep an eye on the dma
//position, as we clear it and set it to the end well before the interrupt, the game assumes it's finished,
//then proceeds to reverse the dma before we have even done it ourselves. So lets just make sure VIF is ready :)
if (vif1ch.qwc > 0 || isStalled == false){
if (vif1ch.qwc > 0 || isStalled == false)
{
vif1ch.qwc = 0;
hwDmacIrq(DMAC_VIF1);
vif1ch.chcr.STR = false;
@ -268,7 +277,7 @@ __fi void vif1STAT(u32 value) {
if (vif1Regs.stat.FDR) // Vif transferring to memory.
{
// Hack but it checks this is true before transfer? (fatal frame)
// Hack but it checks this is true before transfer? (fatal frame)
// Update Refraction: Use of this function has been investigated and understood.
// Before this ever happens, a DIRECT/HL command takes place sending the transfer info to the GS
// One of the registers told about this is TRXREG which tells us how much data is going to transfer (th x tw) in words
@ -277,74 +286,137 @@ __fi void vif1STAT(u32 value) {
vif1Regs.stat.FQC = std::min((u32)16, vif1.GSLastDownloadSize);
//Console.Warning("Reversing VIF Transfer for %x QWC", vif1.GSLastDownloadSize);
}
else // Memory transferring to Vif.
{
//Sometimes the value from the GS is bigger than vif wanted, so it just sets it back and cancels it.
//Other times it can read it off ;)
vif1Regs.stat.FQC = 0;
if (vif1ch.chcr.STR) CPU_INT(DMAC_VIF1, 0);
if (vif1ch.chcr.STR)
CPU_INT(DMAC_VIF1, 0);
}
}
#define caseVif(x) (idx ? VIF1_##x : VIF0_##x)
_vifT __fi u32 vifRead32(u32 mem) {
_vifT __fi u32 vifRead32(u32 mem)
{
vifStruct& vif = MTVU_VifX;
bool wait = idx && THREAD_VU1;
switch (mem) {
case caseVif(ROW0): if (wait) vu1Thread.WaitVU(); return vif.MaskRow._u32[0];
case caseVif(ROW1): if (wait) vu1Thread.WaitVU(); return vif.MaskRow._u32[1];
case caseVif(ROW2): if (wait) vu1Thread.WaitVU(); return vif.MaskRow._u32[2];
case caseVif(ROW3): if (wait) vu1Thread.WaitVU(); return vif.MaskRow._u32[3];
switch (mem)
{
case caseVif(ROW0):
if (wait)
vu1Thread.WaitVU();
return vif.MaskRow._u32[0];
case caseVif(ROW1):
if (wait)
vu1Thread.WaitVU();
return vif.MaskRow._u32[1];
case caseVif(ROW2):
if (wait)
vu1Thread.WaitVU();
return vif.MaskRow._u32[2];
case caseVif(ROW3):
if (wait)
vu1Thread.WaitVU();
return vif.MaskRow._u32[3];
case caseVif(COL0): if (wait) vu1Thread.WaitVU(); return vif.MaskCol._u32[0];
case caseVif(COL1): if (wait) vu1Thread.WaitVU(); return vif.MaskCol._u32[1];
case caseVif(COL2): if (wait) vu1Thread.WaitVU(); return vif.MaskCol._u32[2];
case caseVif(COL3): if (wait) vu1Thread.WaitVU(); return vif.MaskCol._u32[3];
case caseVif(COL0):
if (wait)
vu1Thread.WaitVU();
return vif.MaskCol._u32[0];
case caseVif(COL1):
if (wait)
vu1Thread.WaitVU();
return vif.MaskCol._u32[1];
case caseVif(COL2):
if (wait)
vu1Thread.WaitVU();
return vif.MaskCol._u32[2];
case caseVif(COL3):
if (wait)
vu1Thread.WaitVU();
return vif.MaskCol._u32[3];
}
return psHu32(mem);
}
// returns FALSE if no writeback is needed (or writeback is handled internally)
// returns TRUE if the caller should writeback the value to the eeHw register map.
_vifT __fi bool vifWrite32(u32 mem, u32 value) {
_vifT __fi bool vifWrite32(u32 mem, u32 value)
{
vifStruct& vif = GetVifX;
switch (mem) {
switch (mem)
{
case caseVif(MARK):
VIF_LOG("VIF%d_MARK write32 0x%8.8x", idx, value);
vifXRegs.stat.MRK = false;
//vifXRegs.mark = value;
break;
break;
case caseVif(FBRST):
if (!idx) vif0FBRST(value);
else vif1FBRST(value);
return false;
if (!idx)
vif0FBRST(value);
else
vif1FBRST(value);
return false;
case caseVif(STAT):
if (idx) { // Only Vif1 does this stuff?
if (idx)
{ // Only Vif1 does this stuff?
vif1STAT(value);
}
return false;
return false;
case caseVif(ERR):
case caseVif(MODE):
// standard register writes -- handled by caller.
break;
break;
case caseVif(ROW0): vif.MaskRow._u32[0] = value; if (idx && THREAD_VU1) vu1Thread.WriteRow(vif); return false;
case caseVif(ROW1): vif.MaskRow._u32[1] = value; if (idx && THREAD_VU1) vu1Thread.WriteRow(vif); return false;
case caseVif(ROW2): vif.MaskRow._u32[2] = value; if (idx && THREAD_VU1) vu1Thread.WriteRow(vif); return false;
case caseVif(ROW3): vif.MaskRow._u32[3] = value; if (idx && THREAD_VU1) vu1Thread.WriteRow(vif); return false;
case caseVif(ROW0):
vif.MaskRow._u32[0] = value;
if (idx && THREAD_VU1)
vu1Thread.WriteRow(vif);
return false;
case caseVif(ROW1):
vif.MaskRow._u32[1] = value;
if (idx && THREAD_VU1)
vu1Thread.WriteRow(vif);
return false;
case caseVif(ROW2):
vif.MaskRow._u32[2] = value;
if (idx && THREAD_VU1)
vu1Thread.WriteRow(vif);
return false;
case caseVif(ROW3):
vif.MaskRow._u32[3] = value;
if (idx && THREAD_VU1)
vu1Thread.WriteRow(vif);
return false;
case caseVif(COL0): vif.MaskCol._u32[0] = value; if (idx && THREAD_VU1) vu1Thread.WriteCol(vif); return false;
case caseVif(COL1): vif.MaskCol._u32[1] = value; if (idx && THREAD_VU1) vu1Thread.WriteCol(vif); return false;
case caseVif(COL2): vif.MaskCol._u32[2] = value; if (idx && THREAD_VU1) vu1Thread.WriteCol(vif); return false;
case caseVif(COL3): vif.MaskCol._u32[3] = value; if (idx && THREAD_VU1) vu1Thread.WriteCol(vif); return false;
case caseVif(COL0):
vif.MaskCol._u32[0] = value;
if (idx && THREAD_VU1)
vu1Thread.WriteCol(vif);
return false;
case caseVif(COL1):
vif.MaskCol._u32[1] = value;
if (idx && THREAD_VU1)
vu1Thread.WriteCol(vif);
return false;
case caseVif(COL2):
vif.MaskCol._u32[2] = value;
if (idx && THREAD_VU1)
vu1Thread.WriteCol(vif);
return false;
case caseVif(COL3):
vif.MaskCol._u32[3] = value;
if (idx && THREAD_VU1)
vu1Thread.WriteCol(vif);
return false;
}
// fall-through case: issue standard writeback behavior.

View File

@ -22,12 +22,16 @@
#include "VUmicro.h"
#include "MTVU.h"
#define vifOp(vifCodeName) _vifT int __fastcall vifCodeName(int pass, const u32 *data)
#define pass1 if (pass == 0)
#define pass2 if (pass == 1)
#define pass3 if (pass == 2)
#define vifOp(vifCodeName) _vifT int __fastcall vifCodeName(int pass, const u32* data)
#define pass1 if (pass == 0)
#define pass2 if (pass == 1)
#define pass3 if (pass == 2)
#define pass1or2 if (pass == 0 || pass == 1)
#define vif1Only() { if (!idx) return vifCode_Null<idx>(pass, (u32*)data); }
#define vif1Only() \
{ \
if (!idx) \
return vifCode_Null<idx>(pass, (u32*)data); \
}
vifOp(vifCode_Null);
//------------------------------------------------------------------
@ -41,8 +45,10 @@ __ri void vifExecQueue(int idx)
GetVifX.queued_program = false;
if (!idx) vu0ExecMicro(vif0.queued_pc);
else vu1ExecMicro(vif1.queued_pc);
if (!idx)
vu0ExecMicro(vif0.queued_pc);
else
vu1ExecMicro(vif1.queued_pc);
// Hack for Wakeboarding Unleashed, game runs a VU program in parallel with a VIF unpack list.
// The start of the VU program clears the VU memory, while VIF populates it from behind, so we need to get the clear out of the way.
@ -53,40 +59,48 @@ __ri void vifExecQueue(int idx)
}*/
}
static __fi void vifFlush(int idx) {
static __fi void vifFlush(int idx)
{
vifExecQueue(idx);
if (!idx) vif0FLUSH();
else vif1FLUSH();
if (!idx)
vif0FLUSH();
else
vif1FLUSH();
vifExecQueue(idx);
}
static __fi void vuExecMicro(int idx, u32 addr) {
static __fi void vuExecMicro(int idx, u32 addr)
{
VIFregisters& vifRegs = vifXRegs;
vifFlush(idx);
if(GetVifX.waitforvu)
if (GetVifX.waitforvu)
return;
if (vifRegs.itops > (idx ? 0x3ffu : 0xffu)) {
if (vifRegs.itops > (idx ? 0x3ffu : 0xffu))
{
Console.WriteLn("VIF%d ITOP overrun! %x", idx, vifRegs.itops);
vifRegs.itops &= (idx ? 0x3ffu : 0xffu);
}
vifRegs.itop = vifRegs.itops;
if (idx) {
if (idx)
{
// in case we're handling a VIF1 execMicro, set the top with the tops value
vifRegs.top = vifRegs.tops & 0x3ff;
// is DBF flag set in VIF_STAT?
if (vifRegs.stat.DBF) {
if (vifRegs.stat.DBF)
{
// it is, so set tops with base, and clear the stat DBF flag
vifRegs.tops = vifRegs.base;
vifRegs.stat.DBF = false;
}
else {
else
{
// it is not, so set tops with base + offset, and set stat DBF flag
vifRegs.tops = vifRegs.base + vifRegs.ofst;
vifRegs.stat.DBF = true;
@ -108,13 +122,13 @@ void ExecuteVU(int idx)
{
vifStruct& vifX = GetVifX;
if((vifX.cmd & 0x7f) == 0x17)
if ((vifX.cmd & 0x7f) == 0x17)
{
vuExecMicro(idx, -1);
vifX.cmd = 0;
vifX.pass = 0;
}
else if((vifX.cmd & 0x7f) == 0x14 || (vifX.cmd & 0x7f) == 0x15)
else if ((vifX.cmd & 0x7f) == 0x14 || (vifX.cmd & 0x7f) == 0x15)
{
vuExecMicro(idx, (u16)(vifXRegs.code));
vifX.cmd = 0;
@ -127,44 +141,58 @@ void ExecuteVU(int idx)
// Vif0/Vif1 Code Implementations
//------------------------------------------------------------------
vifOp(vifCode_Base) {
vifOp(vifCode_Base)
{
vif1Only();
pass1 { vif1Regs.base = vif1Regs.code & 0x3ff; vif1.cmd = 0; vif1.pass = 0; }
pass1
{
vif1Regs.base = vif1Regs.code & 0x3ff;
vif1.cmd = 0;
vif1.pass = 0;
}
pass3 { VifCodeLog("Base"); }
return 1;
}
template<int idx> __fi int _vifCode_Direct(int pass, const u8* data, bool isDirectHL) {
template <int idx>
__fi int _vifCode_Direct(int pass, const u8* data, bool isDirectHL)
{
vif1Only();
pass1 {
int vifImm = (u16)vif1Regs.code;
vif1.tag.size = vifImm ? (vifImm*4) : (65536*4);
pass1
{
int vifImm = (u16)vif1Regs.code;
vif1.tag.size = vifImm ? (vifImm * 4) : (65536 * 4);
vif1.pass = 1;
return 1;
}
pass2 {
pass2
{
const char* name = isDirectHL ? "DirectHL" : "Direct";
GIF_TRANSFER_TYPE tranType = isDirectHL ? GIF_TRANS_DIRECTHL : GIF_TRANS_DIRECT;
uint size = std::min(vif1.vifpacketsize, vif1.tag.size) * 4; // Get size in bytes
uint ret = gifUnit.TransferGSPacketData(tranType, (u8*)data, size);
uint ret = gifUnit.TransferGSPacketData(tranType, (u8*)data, size);
vif1.tag.size -= ret/4; // Convert to u32's
vif1.tag.size -= ret / 4; // Convert to u32's
vif1Regs.stat.VGW = false;
if (ret & 3) DevCon.Warning("Vif %s: Ret wasn't a multiple of 4!", name); // Shouldn't happen
if (size == 0) DevCon.Warning("Vif %s: No Data Transfer?", name); // Can this happen?
if (size != ret) { // Stall if gif didn't process all the data (path2 queued)
if (ret & 3)
DevCon.Warning("Vif %s: Ret wasn't a multiple of 4!", name); // Shouldn't happen
if (size == 0)
DevCon.Warning("Vif %s: No Data Transfer?", name); // Can this happen?
if (size != ret)
{ // Stall if gif didn't process all the data (path2 queued)
GUNIT_WARN("Vif %s: Stall! [size=%d][ret=%d]", name, size, ret);
//gifUnit.PrintInfo();
vif1.vifstalled.enabled = VifStallEnable(vif1ch);
vif1.vifstalled.enabled = VifStallEnable(vif1ch);
vif1.vifstalled.value = VIF_TIMING_BREAK;
vif1Regs.stat.VGW = true;
return 0;
}
if (vif1.tag.size == 0) {
if (vif1.tag.size == 0)
{
vif1.cmd = 0;
vif1.pass = 0;
vif1.vifstalled.enabled = VifStallEnable(vif1ch);
vif1.vifstalled.enabled = VifStallEnable(vif1ch);
vif1.vifstalled.value = VIF_TIMING_BREAK;
}
return ret / 4;
@ -172,56 +200,63 @@ template<int idx> __fi int _vifCode_Direct(int pass, const u8* data, bool isDire
return 0;
}
vifOp(vifCode_Direct) {
vifOp(vifCode_Direct)
{
pass3 { VifCodeLog("Direct"); }
return _vifCode_Direct<idx>(pass, (u8*)data, 0);
}
vifOp(vifCode_DirectHL) {
vifOp(vifCode_DirectHL)
{
pass3 { VifCodeLog("DirectHL"); }
return _vifCode_Direct<idx>(pass, (u8*)data, 1);
}
vifOp(vifCode_Flush) {
vifOp(vifCode_Flush)
{
vif1Only();
//vifStruct& vifX = GetVifX;
pass1or2 {
pass1or2
{
bool p1or2 = (gifRegs.stat.APATH != 0 && gifRegs.stat.APATH != 3);
vif1Regs.stat.VGW = false;
vifFlush(idx);
if (gifUnit.checkPaths(1,1,0) || p1or2) {
if (gifUnit.checkPaths(1, 1, 0) || p1or2)
{
GUNIT_WARN("Vif Flush: Stall!");
//gifUnit.PrintInfo();
vif1Regs.stat.VGW = true;
vif1.vifstalled.enabled = VifStallEnable(vif1ch);
vif1.vifstalled.enabled = VifStallEnable(vif1ch);
vif1.vifstalled.value = VIF_TIMING_BREAK;
return 0;
}
else vif1.cmd = 0;
else
vif1.cmd = 0;
vif1.pass = 0;
}
pass3 { VifCodeLog("Flush"); }
return 1;
}
vifOp(vifCode_FlushA) {
vifOp(vifCode_FlushA)
{
vif1Only();
//vifStruct& vifX = GetVifX;
pass1or2 {
pass1or2
{
//Gif_Path& p3 = gifUnit.gifPath[GIF_PATH_3];
u32 gifBusy = gifUnit.checkPaths(1,1,1) || (gifRegs.stat.APATH != 0);
u32 gifBusy = gifUnit.checkPaths(1, 1, 1) || (gifRegs.stat.APATH != 0);
//bool doStall = false;
vif1Regs.stat.VGW = false;
vifFlush(idx);
if (gifBusy)
if (gifBusy)
{
GUNIT_WARN("Vif FlushA: Stall!");
vif1Regs.stat.VGW = true;
vif1.vifstalled.enabled = VifStallEnable(vif1ch);
vif1.vifstalled.enabled = VifStallEnable(vif1ch);
vif1.vifstalled.value = VIF_TIMING_BREAK;
return 0;
}
vif1.cmd = 0;
vif1.pass = 0;
@ -231,32 +266,47 @@ vifOp(vifCode_FlushA) {
}
// ToDo: FixMe
vifOp(vifCode_FlushE) {
vifOp(vifCode_FlushE)
{
vifStruct& vifX = GetVifX;
pass1 { vifFlush(idx); vifX.cmd = 0; vifX.pass = 0;}
pass1
{
vifFlush(idx);
vifX.cmd = 0;
vifX.pass = 0;
}
pass3 { VifCodeLog("FlushE"); }
return 1;
}
vifOp(vifCode_ITop) {
pass1 { vifXRegs.itops = vifXRegs.code & 0x3ff; GetVifX.cmd = 0; GetVifX.pass = 0; }
vifOp(vifCode_ITop)
{
pass1
{
vifXRegs.itops = vifXRegs.code & 0x3ff;
GetVifX.cmd = 0;
GetVifX.pass = 0;
}
pass3 { VifCodeLog("ITop"); }
return 1;
}
vifOp(vifCode_Mark) {
vifOp(vifCode_Mark)
{
vifStruct& vifX = GetVifX;
pass1 {
vifXRegs.mark = (u16)vifXRegs.code;
pass1
{
vifXRegs.mark = (u16)vifXRegs.code;
vifXRegs.stat.MRK = true;
vifX.cmd = 0;
vifX.pass = 0;
vifX.cmd = 0;
vifX.pass = 0;
}
pass3 { VifCodeLog("Mark"); }
return 1;
}
static __fi void _vifCode_MPG(int idx, u32 addr, const u32 *data, int size) {
static __fi void _vifCode_MPG(int idx, u32 addr, const u32* data, int size)
{
VURegs& VUx = idx ? VU1 : VU0;
vifStruct& vifX = GetVifX;
u16 vuMemSize = idx ? 0x4000 : 0x1000;
@ -264,7 +314,8 @@ static __fi void _vifCode_MPG(int idx, u32 addr, const u32 *data, int size) {
vifExecQueue(idx);
if (idx && THREAD_VU1) {
if (idx && THREAD_VU1)
{
if ((addr + size * 4) > vuMemSize)
{
vu1Thread.WriteMicroMem(addr, (u8*)data, vuMemSize - addr);
@ -282,12 +333,14 @@ static __fi void _vifCode_MPG(int idx, u32 addr, const u32 *data, int size) {
}
// Don't forget the Unsigned designator for these checks
if((addr + size *4) > vuMemSize)
if ((addr + size * 4) > vuMemSize)
{
//DevCon.Warning("Handling split MPG");
if (!idx) CpuVU0->Clear(addr, vuMemSize - addr);
else CpuVU1->Clear(addr, vuMemSize - addr);
if (!idx)
CpuVU0->Clear(addr, vuMemSize - addr);
else
CpuVU1->Clear(addr, vuMemSize - addr);
memcpy(VUx.Micro + addr, data, vuMemSize - addr);
size -= (vuMemSize - addr) / 4;
data += (vuMemSize - addr) / 4;
@ -297,51 +350,61 @@ static __fi void _vifCode_MPG(int idx, u32 addr, const u32 *data, int size) {
}
else
{
//The compare is pretty much a waste of time, likelyhood is that the program isnt there, thats why its copying it.
//Faster without.
//if (memcmp_mmx(VUx.Micro + addr, data, size*4)) {
//The compare is pretty much a waste of time, likelyhood is that the program isnt there, thats why its copying it.
//Faster without.
//if (memcmp_mmx(VUx.Micro + addr, data, size*4)) {
// Clear VU memory before writing!
if (!idx) CpuVU0->Clear(addr, size*4);
else CpuVU1->Clear(addr, size*4);
memcpy(VUx.Micro + addr, data, size*4); //from tests, memcpy is 1fps faster on Grandia 3 than memcpy
if (!idx)
CpuVU0->Clear(addr, size * 4);
else
CpuVU1->Clear(addr, size * 4);
memcpy(VUx.Micro + addr, data, size * 4); //from tests, memcpy is 1fps faster on Grandia 3 than memcpy
vifX.tag.addr += size * 4;
}
}
vifOp(vifCode_MPG) {
vifOp(vifCode_MPG)
{
vifStruct& vifX = GetVifX;
pass1 {
int vifNum = (u8)(vifXRegs.code >> 16);
vifX.tag.addr = (u16)(vifXRegs.code << 3) & (idx ? 0x3fff : 0xfff);
vifX.tag.size = vifNum ? (vifNum*2) : 512;
pass1
{
int vifNum = (u8)(vifXRegs.code >> 16);
vifX.tag.addr = (u16)(vifXRegs.code << 3) & (idx ? 0x3fff : 0xfff);
vifX.tag.size = vifNum ? (vifNum * 2) : 512;
vifFlush(idx);
if(vifX.vifstalled.enabled) return 0;
if (vifX.vifstalled.enabled)
return 0;
else
{
vifX.pass = 1;
return 1;
}
}
pass2 {
if (vifX.vifpacketsize < vifX.tag.size) { // Partial Transfer
if((vifX.tag.addr + vifX.vifpacketsize*4) > (idx ? 0x4000 : 0x1000)) {
pass2
{
if (vifX.vifpacketsize < vifX.tag.size)
{ // Partial Transfer
if ((vifX.tag.addr + vifX.vifpacketsize * 4) > (idx ? 0x4000 : 0x1000))
{
//DevCon.Warning("Vif%d MPG Split Overflow", idx);
}
_vifCode_MPG(idx, vifX.tag.addr, data, vifX.vifpacketsize);
_vifCode_MPG(idx, vifX.tag.addr, data, vifX.vifpacketsize);
vifX.tag.size -= vifX.vifpacketsize; //We can do this first as its passed as a pointer
return vifX.vifpacketsize;
}
else { // Full Transfer
if((vifX.tag.addr + vifX.tag.size*4) > (idx ? 0x4000 : 0x1000)) {
else
{ // Full Transfer
if ((vifX.tag.addr + vifX.tag.size * 4) > (idx ? 0x4000 : 0x1000))
{
//DevCon.Warning("Vif%d MPG Split Overflow full %x", idx, vifX.tag.addr + vifX.tag.size*4);
}
_vifCode_MPG(idx, vifX.tag.addr, data, vifX.tag.size);
_vifCode_MPG(idx, vifX.tag.addr, data, vifX.tag.size);
int ret = vifX.tag.size;
vifX.tag.size = 0;
vifX.cmd = 0;
vifX.pass = 0;
vifX.cmd = 0;
vifX.pass = 0;
return ret;
}
}
@ -349,43 +412,48 @@ vifOp(vifCode_MPG) {
return 0;
}
vifOp(vifCode_MSCAL) {
vifOp(vifCode_MSCAL)
{
vifStruct& vifX = GetVifX;
pass1 {
vifFlush(idx);
pass1
{
vifFlush(idx);
if(!vifX.waitforvu)
if (!vifX.waitforvu)
{
vuExecMicro(idx, (u16)(vifXRegs.code));
vuExecMicro(idx, (u16)(vifXRegs.code));
vifX.cmd = 0;
vifX.pass = 0;
if(GetVifX.vifpacketsize > 1)
if (GetVifX.vifpacketsize > 1)
{
//Warship Gunner 2 has a rather big dislike for the delays
if(((data[1] >> 24) & 0x60) == 0x60) // Immediate following Unpack
{
if (((data[1] >> 24) & 0x60) == 0x60) // Immediate following Unpack
{
//Snowblind games only use MSCAL, so other MS kicks force the program directly.
vifExecQueue(idx);
}
}
}
}
}
pass3 { VifCodeLog("MSCAL"); }
return 1;
}
vifOp(vifCode_MSCALF) {
vifOp(vifCode_MSCALF)
{
vifStruct& vifX = GetVifX;
pass1or2 {
pass1or2
{
vifXRegs.stat.VGW = false;
vifFlush(idx);
if (u32 a = gifUnit.checkPaths(1,1,0)) {
GUNIT_WARN("Vif MSCALF: Stall! [%d,%d]", !!(a&1), !!(a&2));
if (u32 a = gifUnit.checkPaths(1, 1, 0))
{
GUNIT_WARN("Vif MSCALF: Stall! [%d,%d]", !!(a & 1), !!(a & 2));
vif1Regs.stat.VGW = true;
vifX.vifstalled.enabled = VifStallEnable(vifXch);
vifX.vifstalled.enabled = VifStallEnable(vifXch);
vifX.vifstalled.value = VIF_TIMING_BREAK;
}
if(!vifX.waitforvu)
if (!vifX.waitforvu)
{
vuExecMicro(idx, (u16)(vifXRegs.code));
vifX.cmd = 0;
@ -397,11 +465,13 @@ vifOp(vifCode_MSCALF) {
return 1;
}
vifOp(vifCode_MSCNT) {
vifOp(vifCode_MSCNT)
{
vifStruct& vifX = GetVifX;
pass1 {
vifFlush(idx);
if(!vifX.waitforvu)
pass1
{
vifFlush(idx);
if (!vifX.waitforvu)
{
vuExecMicro(idx, -1);
vifX.cmd = 0;
@ -420,13 +490,16 @@ vifOp(vifCode_MSCNT) {
}
// ToDo: FixMe
vifOp(vifCode_MskPath3) {
vifOp(vifCode_MskPath3)
{
vif1Only();
pass1 {
pass1
{
vif1Regs.mskpath3 = (vif1Regs.code >> 15) & 0x1;
gifRegs.stat.M3P = (vif1Regs.code >> 15) & 0x1;
gifRegs.stat.M3P = (vif1Regs.code >> 15) & 0x1;
GUNIT_LOG("Vif1 - MskPath3 [p3 = %s]", vif1Regs.mskpath3 ? "masked" : "enabled");
if(!vif1Regs.mskpath3) {
if (!vif1Regs.mskpath3)
{
GUNIT_WARN("VIF MSKPATH3 off Path3 triggering!");
gifInterrupt();
}
@ -437,17 +510,19 @@ vifOp(vifCode_MskPath3) {
return 1;
}
vifOp(vifCode_Nop) {
pass1 {
vifOp(vifCode_Nop)
{
pass1
{
GetVifX.cmd = 0;
GetVifX.pass = 0;
vifExecQueue(idx);
if (GetVifX.vifpacketsize > 1)
{
if(((data[1] >> 24) & 0x7f) == 0x6 && (data[1] & 0x1)) //is mskpath3 next
{
GetVifX.vifstalled.enabled = VifStallEnable(vifXch);
if (((data[1] >> 24) & 0x7f) == 0x6 && (data[1] & 0x1)) //is mskpath3 next
{
GetVifX.vifstalled.enabled = VifStallEnable(vifXch);
GetVifX.vifstalled.value = VIF_TIMING_BREAK;
}
}
@ -457,11 +532,14 @@ vifOp(vifCode_Nop) {
}
// ToDo: Review Flags
vifOp(vifCode_Null) {
vifOp(vifCode_Null)
{
vifStruct& vifX = GetVifX;
pass1 {
pass1
{
// if ME1, then force the vif to interrupt
if (!(vifXRegs.err.ME1)) { // Ignore vifcode and tag mismatch error
if (!(vifXRegs.err.ME1))
{ // Ignore vifcode and tag mismatch error
Console.WriteLn("Vif%d: Unknown VifCmd! [%x]", idx, vifX.cmd);
vifXRegs.stat.ER1 = true;
vifX.vifstalled.enabled = VifStallEnable(vifXch);
@ -472,34 +550,40 @@ vifOp(vifCode_Null) {
vifX.pass = 0;
//If the top bit was set to interrupt, we don't want it to take commands from a bad code
if (vifXRegs.code & 0x80000000) vifX.irq = 0;
if (vifXRegs.code & 0x80000000)
vifX.irq = 0;
}
pass2 { Console.Error("Vif%d bad vifcode! [CMD = %x]", idx, vifX.cmd); }
pass3 { VifCodeLog("Null"); }
return 1;
}
vifOp(vifCode_Offset) {
vifOp(vifCode_Offset)
{
vif1Only();
pass1 {
vif1Regs.stat.DBF = false;
vif1Regs.ofst = vif1Regs.code & 0x3ff;
vif1Regs.tops = vif1Regs.base;
vif1.cmd = 0;
vif1.pass = 0;
pass1
{
vif1Regs.stat.DBF = false;
vif1Regs.ofst = vif1Regs.code & 0x3ff;
vif1Regs.tops = vif1Regs.base;
vif1.cmd = 0;
vif1.pass = 0;
}
pass3 { VifCodeLog("Offset"); }
return 1;
}
template<int idx> static __fi int _vifCode_STColRow(const u32* data, u32* pmem2) {
template <int idx>
static __fi int _vifCode_STColRow(const u32* data, u32* pmem2)
{
vifStruct& vifX = GetVifX;
int ret = std::min(4 - vifX.tag.addr, vifX.vifpacketsize);
pxAssume(vifX.tag.addr < 4);
pxAssume(ret > 0);
switch (ret) {
switch (ret)
{
case 4:
pmem2[3] = data[3];
[[fallthrough]];
@ -511,8 +595,8 @@ template<int idx> static __fi int _vifCode_STColRow(const u32* data, u32* pmem2)
[[fallthrough]];
case 1:
pmem2[0] = data[0];
break;
jNO_DEFAULT
break;
jNO_DEFAULT
}
vifX.tag.addr += ret;
@ -523,20 +607,23 @@ template<int idx> static __fi int _vifCode_STColRow(const u32* data, u32* pmem2)
vifX.cmd = 0;
}
return ret;
}
vifOp(vifCode_STCol) {
vifOp(vifCode_STCol)
{
vifStruct& vifX = GetVifX;
pass1 {
pass1
{
vifX.tag.addr = 0;
vifX.tag.size = 4;
vifX.pass = 1;
return 1;
}
pass2 {
pass2
{
u32 ret = _vifCode_STColRow<idx>(data, &vifX.MaskCol._u32[vifX.tag.addr]);
if (idx && vifX.tag.size == 0)
vu1Thread.WriteCol(vifX);
@ -546,15 +633,18 @@ vifOp(vifCode_STCol) {
return 0;
}
vifOp(vifCode_STRow) {
vifOp(vifCode_STRow)
{
vifStruct& vifX = GetVifX;
pass1 {
pass1
{
vifX.tag.addr = 0;
vifX.tag.size = 4;
vifX.pass = 1;
return 1;
}
pass2 {
pass2
{
u32 ret = _vifCode_STColRow<idx>(data, &vifX.MaskRow._u32[vifX.tag.addr]);
if (idx && vifX.tag.size == 0)
vu1Thread.WriteRow(vifX);
@ -564,65 +654,89 @@ vifOp(vifCode_STRow) {
return 1;
}
vifOp(vifCode_STCycl) {
vifOp(vifCode_STCycl)
{
vifStruct& vifX = GetVifX;
pass1 {
pass1
{
vifXRegs.cycle.cl = (u8)(vifXRegs.code);
vifXRegs.cycle.wl = (u8)(vifXRegs.code >> 8);
vifX.cmd = 0;
vifX.pass = 0;
vifX.cmd = 0;
vifX.pass = 0;
}
pass3 { VifCodeLog("STCycl"); }
return 1;
}
vifOp(vifCode_STMask) {
vifOp(vifCode_STMask)
{
vifStruct& vifX = GetVifX;
pass1 { vifX.tag.size = 1; vifX.pass = 1; return 1; }
pass2 { vifXRegs.mask = data[0]; vifX.tag.size = 0; vifX.cmd = 0; vifX.pass = 0;}
pass1
{
vifX.tag.size = 1;
vifX.pass = 1;
return 1;
}
pass2
{
vifXRegs.mask = data[0];
vifX.tag.size = 0;
vifX.cmd = 0;
vifX.pass = 0;
}
pass3 { VifCodeLog("STMask"); }
return 1;
}
vifOp(vifCode_STMod) {
pass1 { vifXRegs.mode = vifXRegs.code & 0x3; GetVifX.cmd = 0; GetVifX.pass = 0;}
vifOp(vifCode_STMod)
{
pass1
{
vifXRegs.mode = vifXRegs.code & 0x3;
GetVifX.cmd = 0;
GetVifX.pass = 0;
}
pass3 { VifCodeLog("STMod"); }
return 1;
}
template< uint idx >
template <uint idx>
static uint calc_addr(bool flg)
{
VIFregisters& vifRegs = vifXRegs;
uint retval = vifRegs.code;
if (idx && flg) retval += vifRegs.tops;
if (idx && flg)
retval += vifRegs.tops;
return retval & (idx ? 0x3ff : 0xff);
}
vifOp(vifCode_Unpack) {
pass1 {
vifOp(vifCode_Unpack)
{
pass1
{
vifUnpackSetup<idx>(data);
return 1;
}
pass2 {
pass2
{
return nVifUnpack<idx>((u8*)data);
}
pass3 {
pass3
{
vifStruct& vifX = GetVifX;
VIFregisters& vifRegs = vifXRegs;
uint vl = vifX.cmd & 0x03;
uint vn = (vifX.cmd >> 2) & 0x3;
bool flg = (vifRegs.code >> 15) & 1;
static const char* const vntbl[] = { "S", "V2", "V3", "V4" };
static const uint vltbl[] = { 32, 16, 8, 5 };
static const char* const vntbl[] = {"S", "V2", "V3", "V4"};
static const uint vltbl[] = {32, 16, 8, 5};
VifCodeLog("Unpack %s_%u (%s) @ 0x%04X%s (cl=%u wl=%u num=0x%02X)",
vntbl[vn], vltbl[vl], (vifX.cmd & 0x10) ? "masked" : "unmasked",
calc_addr<idx>(flg), flg ? "(FLG)" : "",
vifRegs.cycle.cl, vifRegs.cycle.wl, (vifXRegs.code >> 16) & 0xff
);
vifRegs.cycle.cl, vifRegs.cycle.wl, (vifXRegs.code >> 16) & 0xff);
}
return 0;
}
@ -669,4 +783,4 @@ __aligned16 FnType_VifCmdHandler* const vifCmdHandler[2][128] =
vifCode_Unpack<1> , vifCode_Unpack<1> , vifCode_Unpack<1> , vifCode_Unpack<1> , vifCode_Unpack<1> , vifCode_Unpack<1> , vifCode_Unpack<1> , vifCode_Null<1>, /*0x70*/
vifCode_Unpack<1> , vifCode_Unpack<1> , vifCode_Unpack<1> , vifCode_Null<1> , vifCode_Unpack<1> , vifCode_Unpack<1> , vifCode_Unpack<1> , vifCode_Unpack<1> /*0x78*/
}
};
};