2006-06-15 04:19:30 +00:00
|
|
|
#include <assert.h>
|
|
|
|
#include "VIF.h"
|
|
|
|
#include "GIF.h"
|
|
|
|
#include "PS2VM.h"
|
|
|
|
|
|
|
|
using namespace Framework;
|
|
|
|
|
|
|
|
uint32 CVIF::m_VPU_STAT;
|
|
|
|
|
|
|
|
static unsigned int nExecCount = 0;
|
|
|
|
|
|
|
|
CVIF::CVPU* CVIF::m_pVPU[2] =
|
|
|
|
{
|
|
|
|
new CVPU(&CPS2VM::m_pMicroMem0, &CPS2VM::m_pVUMem0, NULL),
|
|
|
|
new CVPU1(&CPS2VM::m_pMicroMem1, &CPS2VM::m_pVUMem1, &CPS2VM::m_VU1),
|
|
|
|
};
|
|
|
|
|
|
|
|
void CVIF::Reset()
|
|
|
|
{
|
|
|
|
m_pVPU[0]->Reset();
|
|
|
|
m_pVPU[1]->Reset();
|
|
|
|
m_VPU_STAT = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CVIF::SaveState(CStream* pStream)
|
|
|
|
{
|
|
|
|
pStream->Write(&m_VPU_STAT, 4);
|
|
|
|
|
|
|
|
m_pVPU[0]->SaveState(pStream);
|
|
|
|
m_pVPU[1]->SaveState(pStream);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CVIF::LoadState(CStream* pStream)
|
|
|
|
{
|
|
|
|
pStream->Read(&m_VPU_STAT, 4);
|
|
|
|
|
|
|
|
m_pVPU[0]->LoadState(pStream);
|
|
|
|
m_pVPU[1]->LoadState(pStream);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CVIF::ReceiveDMA1(uint32 nAddress, uint32 nQWC, bool nTagIncluded)
|
|
|
|
{
|
|
|
|
if(nTagIncluded)
|
|
|
|
{
|
|
|
|
m_pVPU[1]->ProcessPacket(nAddress + 8, (nQWC * 0x10) - 8);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_pVPU[1]->ProcessPacket(nAddress, nQWC * 0x10);
|
|
|
|
}
|
|
|
|
return nQWC;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32* CVIF::GetTop1Address()
|
|
|
|
{
|
|
|
|
return m_pVPU[1]->GetTOP();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CVIF::StopVU(CMIPS* pCtx)
|
|
|
|
{
|
|
|
|
if(pCtx == &CPS2VM::m_VU1)
|
|
|
|
{
|
|
|
|
m_VPU_STAT &= ~STAT_VBS1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CVIF::ProcessXGKICK(uint32 nAddress)
|
|
|
|
{
|
|
|
|
nAddress &= 0xFFFF;
|
|
|
|
nAddress *= 0x10;
|
|
|
|
|
|
|
|
CGIF::ProcessPacket(CPS2VM::m_pVUMem1, nAddress, CPS2VM::VUMEM1SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CVIF::IsVU1Running()
|
|
|
|
{
|
|
|
|
return (m_VPU_STAT & STAT_VBS1) != 0;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
uint32 CVIF::UnpackV45(uint32 nSrcAddr, uint32 nDstAddr, uint32 nWriteSize, bool nUsn, uint8 nWL, uint8 nCL, uint8* pVUMem)
|
|
|
|
{
|
|
|
|
unsigned int i, nPackets;
|
|
|
|
uint16 nColor;
|
|
|
|
uint32 nAddress;
|
|
|
|
|
|
|
|
if(nCL != nWL)
|
|
|
|
{
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
nPackets = (nWriteSize / 0x10);
|
|
|
|
nAddress = nSrcAddr;
|
|
|
|
|
|
|
|
for(i = 0; i < nPackets; i++)
|
|
|
|
{
|
|
|
|
nColor = *(uint16*)&CPS2VM::m_pRAM[nAddress];
|
|
|
|
|
|
|
|
*(uint32*)&pVUMem[nDstAddr + 0x0] = ((nColor >> 0) & 0x1F) << 3;
|
|
|
|
*(uint32*)&pVUMem[nDstAddr + 0x4] = ((nColor >> 5) & 0x1F) << 3;
|
|
|
|
*(uint32*)&pVUMem[nDstAddr + 0x8] = ((nColor >> 10) & 0x1F) << 3;
|
|
|
|
*(uint32*)&pVUMem[nDstAddr + 0xC] = ((nColor >> 15) & 0x01) << 7;
|
|
|
|
|
|
|
|
nDstAddr += 0x10;
|
|
|
|
nAddress += 0x02;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Force word alignment
|
|
|
|
if(nAddress & 0x03)
|
|
|
|
{
|
|
|
|
nAddress += 0x02;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nAddress - nSrcAddr;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
// VPU Class Implementation
|
|
|
|
|
|
|
|
CVIF::CVPU::CVPU(uint8** pMicroMem, uint8** pVUMem, CMIPS* pCtx)
|
|
|
|
{
|
|
|
|
m_pMicroMem = pMicroMem;
|
|
|
|
m_pVUMem = pVUMem;
|
|
|
|
m_pCtx = pCtx;
|
|
|
|
}
|
|
|
|
|
|
|
|
CVIF::CVPU::~CVPU()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void CVIF::CVPU::Reset()
|
|
|
|
{
|
|
|
|
memset(&m_STAT, 0, sizeof(STAT));
|
|
|
|
memset(&m_CODE, 0, sizeof(CODE));
|
|
|
|
memset(&m_CYCLE, 0, sizeof(CYCLE));
|
|
|
|
m_NUM = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CVIF::CVPU::SaveState(CStream* pStream)
|
|
|
|
{
|
|
|
|
pStream->Write(&m_STAT, sizeof(STAT));
|
|
|
|
pStream->Write(&m_CODE, sizeof(CODE));
|
|
|
|
pStream->Write(&m_CYCLE, sizeof(CYCLE));
|
|
|
|
pStream->Write(&m_NUM, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CVIF::CVPU::LoadState(CStream* pStream)
|
|
|
|
{
|
|
|
|
pStream->Read(&m_STAT, sizeof(STAT));
|
|
|
|
pStream->Read(&m_CODE, sizeof(CODE));
|
|
|
|
pStream->Read(&m_CYCLE, sizeof(CYCLE));
|
|
|
|
pStream->Read(&m_NUM, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32* CVIF::CVPU::GetTOP()
|
|
|
|
{
|
|
|
|
assert(0);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CVIF::CVPU::ProcessPacket(uint32 nAddress, uint32 nSize)
|
|
|
|
{
|
|
|
|
CODE Code;
|
|
|
|
uint32 nEnd;
|
|
|
|
|
|
|
|
nEnd = nAddress + nSize;
|
|
|
|
|
|
|
|
while(nAddress < nEnd)
|
|
|
|
{
|
|
|
|
if(m_STAT.nVPS == 1)
|
|
|
|
{
|
|
|
|
//Command is waiting for more data...
|
|
|
|
nAddress += ExecuteCommand(m_CODE, nAddress, (nEnd - nAddress));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Code = *(CODE*)&CPS2VM::m_pRAM[nAddress];
|
|
|
|
|
|
|
|
nAddress += 4;
|
|
|
|
|
|
|
|
assert(Code.nI == 0);
|
|
|
|
|
|
|
|
m_NUM = Code.nNUM;
|
|
|
|
m_CODE = Code;
|
|
|
|
|
|
|
|
nAddress += ExecuteCommand(Code, nAddress, (nEnd - nAddress));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CVIF::CVPU::ExecuteCommand(CODE nCommand, uint32 nAddress, uint32 nSize)
|
|
|
|
{
|
|
|
|
if(nCommand.nCMD >= 0x60)
|
|
|
|
{
|
|
|
|
return Cmd_UNPACK(nCommand, nAddress, nSize);
|
|
|
|
}
|
|
|
|
switch(nCommand.nCMD)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
//NOP
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case 0x01:
|
|
|
|
//STCYCL
|
|
|
|
m_CYCLE = nCommand.nIMM;
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case 0x14:
|
|
|
|
//MSCAL
|
|
|
|
assert(0);
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case 0x17:
|
|
|
|
//MSCNT
|
|
|
|
assert(0);
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case 0x4A:
|
|
|
|
//MPG
|
|
|
|
return Cmd_MPG(nCommand, nAddress, nSize);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(0);
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CVIF::CVPU::ExecuteMicro(uint32 nAddress, uint32 nMask)
|
|
|
|
{
|
|
|
|
//--- REMOVE
|
|
|
|
nExecCount++;
|
|
|
|
// if((nExecCount > 20))
|
|
|
|
// {
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
//--- REMOVE
|
|
|
|
|
|
|
|
m_pCtx->m_State.nPC = nAddress;
|
|
|
|
m_VPU_STAT |= nMask;
|
|
|
|
#ifndef VU_DEBUG
|
|
|
|
while(m_VPU_STAT & nMask)
|
|
|
|
{
|
|
|
|
m_pCtx->Execute(100000);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CVIF::CVPU::Cmd_MPG(CODE nCommand, uint32 nAddress, uint32 nSize)
|
|
|
|
{
|
|
|
|
uint32 nTransfered, nDstAddr, nNum, nCodeNum;
|
|
|
|
|
|
|
|
//--- REMOVE
|
|
|
|
nExecCount = 0;
|
|
|
|
//--- REMOVE
|
|
|
|
|
|
|
|
nNum = (m_NUM == 0) ? (256 * 8) : (m_NUM * 8);
|
|
|
|
nCodeNum = (m_CODE.nNUM == 0) ? (256 * 8) : (m_CODE.nNUM * 8);
|
|
|
|
|
|
|
|
nSize = min(nNum, nSize);
|
|
|
|
|
|
|
|
nTransfered = (nCodeNum - nNum) * 8;
|
|
|
|
nDstAddr = (m_CODE.nIMM * 8) + nTransfered;
|
|
|
|
|
|
|
|
//Check if there's a change
|
|
|
|
if(memcmp((*m_pMicroMem) + nDstAddr, CPS2VM::m_pRAM + nAddress, nSize) != 0)
|
|
|
|
{
|
|
|
|
m_pCtx->m_pExecMap->InvalidateBlocks();
|
|
|
|
memcpy((*m_pMicroMem) + nDstAddr, CPS2VM::m_pRAM + nAddress, nSize);
|
|
|
|
|
|
|
|
//--- REMOVE
|
|
|
|
//*(uint32*)&CPS2VM::m_pMicroMem1[0x380] = 0x8000033C;
|
|
|
|
//*(uint32*)&CPS2VM::m_pMicroMem1[0x410] = 0x8000033C;
|
|
|
|
//--- REMOVE
|
|
|
|
}
|
|
|
|
|
|
|
|
m_NUM -= (uint8)(nSize / 8);
|
|
|
|
if((m_NUM == 0) && (nSize != 0))
|
|
|
|
{
|
|
|
|
m_STAT.nVPS = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_STAT.nVPS = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CVIF::CVPU::Cmd_UNPACK(CODE nCommand, uint32 nAddress, uint32 nSize)
|
|
|
|
{
|
|
|
|
assert(0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CVIF::CVPU::Unpack_V432(uint32 nDstAddr, uint32 nSrcAddr, uint32 nSize)
|
|
|
|
{
|
|
|
|
uint32 nCL, nWL;
|
|
|
|
|
|
|
|
nCL = m_CYCLE.nCL;
|
|
|
|
nWL = m_CYCLE.nWL;
|
|
|
|
|
|
|
|
assert(nCL >= nWL);
|
|
|
|
|
|
|
|
nSize = min(nSize, (uint32)m_NUM * 0x10);
|
|
|
|
|
|
|
|
if(nCL == nWL)
|
|
|
|
{
|
|
|
|
memcpy((*m_pVUMem) + nDstAddr, CPS2VM::m_pRAM + nSrcAddr, nSize);
|
|
|
|
m_NUM -= (uint8)(nSize / 0x10);
|
|
|
|
}
|
|
|
|
else if(nCL > nWL)
|
|
|
|
{
|
|
|
|
uint32 nWritten, nAddrInc;
|
|
|
|
|
|
|
|
for(unsigned int i = 0; i < nSize; i += 0x10)
|
|
|
|
{
|
|
|
|
nWritten = m_CODE.nNUM - m_NUM;
|
|
|
|
nAddrInc = (nCL * (nWritten / nWL) + (nWritten % nWL)) * 0x10;
|
|
|
|
|
|
|
|
memcpy((*m_pVUMem) + nDstAddr + nAddrInc, CPS2VM::m_pRAM + nSrcAddr, 0x10);
|
|
|
|
|
|
|
|
nSrcAddr += 0x10;
|
|
|
|
m_NUM -= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return nSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
// VPU1 Class Implementation
|
|
|
|
|
|
|
|
CVIF::CVPU1::CVPU1(uint8** pMicroMem, uint8** pVUMem, CMIPS* pCtx) :
|
|
|
|
CVPU(pMicroMem, pVUMem, pCtx)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void CVIF::CVPU1::Reset()
|
|
|
|
{
|
|
|
|
CVPU::Reset();
|
|
|
|
m_BASE = 0;
|
|
|
|
m_TOP = 0;
|
|
|
|
m_TOPS = 0;
|
|
|
|
m_OFST = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CVIF::CVPU1::SaveState(CStream* pStream)
|
|
|
|
{
|
|
|
|
CVPU::SaveState(pStream);
|
|
|
|
|
|
|
|
pStream->Write(&m_BASE, 4);
|
|
|
|
pStream->Write(&m_TOP, 4);
|
|
|
|
pStream->Write(&m_TOPS, 4);
|
|
|
|
pStream->Write(&m_OFST, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CVIF::CVPU1::LoadState(CStream* pStream)
|
|
|
|
{
|
|
|
|
CVPU::LoadState(pStream);
|
|
|
|
|
|
|
|
pStream->Read(&m_BASE, 4);
|
|
|
|
pStream->Read(&m_TOP, 4);
|
|
|
|
pStream->Read(&m_TOPS, 4);
|
|
|
|
pStream->Read(&m_OFST, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32* CVIF::CVPU1::GetTOP()
|
|
|
|
{
|
|
|
|
return &m_TOP;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CVIF::CVPU1::ExecuteCommand(CODE nCommand, uint32 nAddress, uint32 nSize)
|
|
|
|
{
|
|
|
|
switch(nCommand.nCMD)
|
|
|
|
{
|
|
|
|
case 0x02:
|
|
|
|
//OFFSET
|
|
|
|
m_OFST = nCommand.nIMM;
|
|
|
|
m_STAT.nDBF = 0;
|
|
|
|
m_TOPS = m_BASE;
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case 0x03:
|
|
|
|
//BASE
|
|
|
|
m_BASE = nCommand.nIMM;
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case 0x06:
|
|
|
|
//MSKPATH3
|
|
|
|
//Should mask bit somewhere...
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case 0x11:
|
|
|
|
//FLUSH
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case 0x13:
|
|
|
|
//FLUSHA
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case 0x14:
|
|
|
|
//MSCAL
|
|
|
|
m_TOP = m_TOPS;
|
|
|
|
|
|
|
|
if(m_STAT.nDBF == 1)
|
|
|
|
{
|
|
|
|
m_TOPS = m_BASE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_TOPS = m_BASE + m_OFST;
|
|
|
|
}
|
|
|
|
m_STAT.nDBF = ~m_STAT.nDBF;
|
|
|
|
|
|
|
|
ExecuteMicro(nCommand.nIMM + CPS2VM::VUMEM1SIZE, STAT_VBS1);
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case 0x17:
|
|
|
|
//MSCNT
|
|
|
|
m_TOP = m_TOPS;
|
|
|
|
|
|
|
|
if(m_STAT.nDBF == 1)
|
|
|
|
{
|
|
|
|
m_TOPS = m_BASE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_TOPS = m_BASE + m_OFST;
|
|
|
|
}
|
|
|
|
m_STAT.nDBF = ~m_STAT.nDBF;
|
|
|
|
|
|
|
|
ExecuteMicro(m_pCtx->m_State.nPC, STAT_VBS1);
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case 0x50:
|
2006-06-26 09:31:14 +00:00
|
|
|
case 0x51:
|
|
|
|
//DIRECT/DIRECTHL
|
2006-06-15 04:19:30 +00:00
|
|
|
return Cmd_DIRECT(nCommand, nAddress, nSize);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return CVPU::ExecuteCommand(nCommand, nAddress, nSize);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CVIF::CVPU1::Cmd_DIRECT(CODE nCommand, uint32 nAddress, uint32 nSize)
|
|
|
|
{
|
2006-06-26 09:31:14 +00:00
|
|
|
nSize = min(m_CODE.nIMM * 0x10, nSize);
|
|
|
|
|
2006-06-15 04:19:30 +00:00
|
|
|
CGIF::ProcessPacket(CPS2VM::m_pRAM, nAddress, nAddress + nSize);
|
|
|
|
|
|
|
|
m_CODE.nIMM -= (nSize / 0x10);
|
|
|
|
if((m_CODE.nIMM == 0) && (nSize != 0))
|
|
|
|
{
|
|
|
|
m_STAT.nVPS = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_STAT.nVPS = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CVIF::CVPU1::Cmd_UNPACK(CODE nCommand, uint32 nAddress, uint32 nSize)
|
|
|
|
{
|
|
|
|
bool nUsn, nFlg;
|
|
|
|
uint32 nDstAddr, nTransfered;
|
|
|
|
|
|
|
|
nFlg = (m_CODE.nIMM & 0x8000) != 0;
|
|
|
|
nUsn = (m_CODE.nIMM & 0x4000) != 0;
|
|
|
|
nDstAddr = (m_CODE.nIMM & 0x03FF);
|
|
|
|
|
|
|
|
if(nFlg)
|
|
|
|
{
|
|
|
|
nDstAddr += m_TOPS;
|
|
|
|
}
|
|
|
|
|
|
|
|
nTransfered = m_CODE.nNUM - m_NUM;
|
|
|
|
nDstAddr += nTransfered;
|
|
|
|
|
|
|
|
nDstAddr *= 0x10;
|
|
|
|
|
|
|
|
switch(nCommand.nCMD & 0x0F)
|
|
|
|
{
|
|
|
|
case 0x0C:
|
|
|
|
//V4-32
|
|
|
|
nSize = Unpack_V432(nDstAddr, nAddress, nSize);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(0);
|
|
|
|
nSize = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m_NUM != 0)
|
|
|
|
{
|
|
|
|
m_STAT.nVPS = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_STAT.nVPS = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nSize;
|
|
|
|
/*
|
|
|
|
if(nFlg == 1 && nUnit == 1)
|
|
|
|
{
|
|
|
|
nImm += (uint16)m_VIF1_TOPS;
|
|
|
|
}
|
|
|
|
|
|
|
|
nImm *= 0x10;
|
|
|
|
nNum *= 0x10;
|
|
|
|
|
|
|
|
nWL = (uint8)(((*pCycle) & 0xFF00) >> 8);
|
|
|
|
nCL = (uint8)(((*pCycle) & 0x00FF) >> 0);
|
|
|
|
|
|
|
|
//Check format
|
|
|
|
switch(nCmd & 0x0F)
|
|
|
|
{
|
|
|
|
case 0x0C:
|
|
|
|
//V4-32
|
|
|
|
nAddress += UnpackV432(nAddress, nImm, nNum, nUsn, nWL, nCL, pVUMemory);
|
|
|
|
break;
|
|
|
|
case 0x0F:
|
|
|
|
//V4-5
|
|
|
|
nAddress += UnpackV45(nAddress, nImm, nNum, nUsn, nWL, nCL, pVUMemory);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|