Play-/Source/ee/Vif.cpp
2015-12-13 21:49:45 -05:00

1256 lines
26 KiB
C++

#include <cassert>
#include <stdexcept>
#include "string_format.h"
#include "../Log.h"
#include "../Ps2Const.h"
#include "../RegisterStateFile.h"
#include "../MemoryStateFile.h"
#include "Vpu.h"
#include "Vif.h"
#define LOG_NAME ("vif")
#define STATE_PATH_REGS_FORMAT ("vpu/vif_%d.xml")
#define STATE_PATH_FIFO_FORMAT ("vpu/vif_%d_fifo")
#define STATE_REGS_STAT ("STAT")
#define STATE_REGS_CODE ("CODE")
#define STATE_REGS_CYCLE ("CYCLE")
#define STATE_REGS_NUM ("NUM")
#define STATE_REGS_MASK ("MASK")
#define STATE_REGS_MODE ("MODE")
#define STATE_REGS_ROW0 ("ROW0")
#define STATE_REGS_ROW1 ("ROW1")
#define STATE_REGS_ROW2 ("ROW2")
#define STATE_REGS_ROW3 ("ROW3")
#define STATE_REGS_COL0 ("COL0")
#define STATE_REGS_COL1 ("COL1")
#define STATE_REGS_COL2 ("COL2")
#define STATE_REGS_COL3 ("COL3")
#define STATE_REGS_MARK ("MARK")
#define STATE_REGS_ITOP ("ITOP")
#define STATE_REGS_ITOPS ("ITOPS")
#define STATE_REGS_READTICK ("readTick")
#define STATE_REGS_WRITETICK ("writeTick")
#define STATE_REGS_FIFOINDEX ("fifoIndex")
CVif::CVif(unsigned int number, CVpu& vpu, uint8* ram, uint8* spr)
: m_number(number)
, m_ram(ram)
, m_spr(spr)
, m_stream(ram, spr)
, m_vpu(vpu)
, m_vifProfilerZone(CProfiler::GetInstance().RegisterZone(string_format("VIF%d", number).c_str()))
{
}
CVif::~CVif()
{
}
void CVif::Reset()
{
memset(&m_STAT, 0, sizeof(STAT));
memset(&m_CODE, 0, sizeof(CODE));
memset(&m_CYCLE, 0, sizeof(CYCLE));
memset(&m_R, 0, sizeof(m_R));
memset(&m_C, 0, sizeof(m_C));
memset(&m_fifoBuffer, 0, sizeof(m_fifoBuffer));
m_fifoIndex = 0;
m_MODE = 0;
m_NUM = 0;
m_MASK = 0;
m_MARK = 0;
m_ITOP = 0;
m_ITOPS = 0;
m_readTick = 0;
m_writeTick = 0;
m_stream.Reset();
#ifdef DELAYED_MSCAL
m_pendingMicroProgram = -1;
memset(&m_previousCODE, 0, sizeof(CODE));
#endif
}
uint32 CVif::GetRegister(uint32 address)
{
uint32 result = 0;
switch(address)
{
case VIF0_MARK:
case VIF1_MARK:
result = m_MARK;
break;
case VIF0_CYCLE:
case VIF1_CYCLE:
result = m_CYCLE;
break;
case VIF0_MODE:
case VIF1_MODE:
result = m_MODE;
break;
case VIF0_R0:
case VIF1_R0:
result = m_R[0];
break;
case VIF0_R1:
case VIF1_R1:
result = m_R[1];
break;
case VIF0_R2:
case VIF1_R2:
result = m_R[2];
break;
case VIF0_R3:
case VIF1_R3:
result = m_R[3];
break;
}
#ifdef _DEBUG
DisassembleGet(address);
#endif
return result;
}
void CVif::SetRegister(uint32 address, uint32 value)
{
if(
(address >= VIF0_FIFO_START && address < VIF0_FIFO_END) ||
(address >= VIF1_FIFO_START && address < VIF1_FIFO_END)
)
{
ProcessFifoWrite(address, value);
}
else
{
switch(address)
{
case VIF1_FBRST:
if(value & FBRST_STC)
{
m_STAT.nVIS = 0;
m_STAT.nINT = 0;
}
break;
case VIF0_MARK:
case VIF1_MARK:
m_MARK = value;
break;
}
}
#ifdef _DEBUG
DisassembleSet(address, value);
#endif
}
void CVif::SaveState(Framework::CZipArchiveWriter& archive)
{
{
auto path = string_format(STATE_PATH_REGS_FORMAT, m_number);
auto registerFile = new CRegisterStateFile(path.c_str());
registerFile->SetRegister32(STATE_REGS_STAT, m_STAT);
registerFile->SetRegister32(STATE_REGS_CODE, m_CODE);
registerFile->SetRegister32(STATE_REGS_CYCLE, m_CYCLE);
registerFile->SetRegister32(STATE_REGS_NUM, m_NUM);
registerFile->SetRegister32(STATE_REGS_MODE, m_MODE);
registerFile->SetRegister32(STATE_REGS_MASK, m_MASK);
registerFile->SetRegister32(STATE_REGS_MARK, m_MARK);
registerFile->SetRegister32(STATE_REGS_ROW0, m_R[0]);
registerFile->SetRegister32(STATE_REGS_ROW1, m_R[1]);
registerFile->SetRegister32(STATE_REGS_ROW2, m_R[2]);
registerFile->SetRegister32(STATE_REGS_ROW3, m_R[3]);
registerFile->SetRegister32(STATE_REGS_COL0, m_C[0]);
registerFile->SetRegister32(STATE_REGS_COL1, m_C[1]);
registerFile->SetRegister32(STATE_REGS_COL2, m_C[2]);
registerFile->SetRegister32(STATE_REGS_COL3, m_C[3]);
registerFile->SetRegister32(STATE_REGS_ITOP, m_ITOP);
registerFile->SetRegister32(STATE_REGS_ITOPS, m_ITOPS);
registerFile->SetRegister32(STATE_REGS_READTICK, m_readTick);
registerFile->SetRegister32(STATE_REGS_WRITETICK, m_writeTick);
registerFile->SetRegister32(STATE_REGS_FIFOINDEX, m_fifoIndex);
archive.InsertFile(registerFile);
}
{
auto path = string_format(STATE_PATH_FIFO_FORMAT, m_number);
archive.InsertFile(new CMemoryStateFile(path.c_str(), &m_fifoBuffer, sizeof(m_fifoBuffer)));
}
}
void CVif::LoadState(Framework::CZipArchiveReader& archive)
{
{
auto path = string_format(STATE_PATH_REGS_FORMAT, m_number);
CRegisterStateFile registerFile(*archive.BeginReadFile(path.c_str()));
m_STAT <<= registerFile.GetRegister32(STATE_REGS_STAT);
m_CODE <<= registerFile.GetRegister32(STATE_REGS_CODE);
m_CYCLE <<= registerFile.GetRegister32(STATE_REGS_CYCLE);
m_NUM = static_cast<uint8>(registerFile.GetRegister32(STATE_REGS_NUM));
m_MODE = registerFile.GetRegister32(STATE_REGS_MODE);
m_MASK = registerFile.GetRegister32(STATE_REGS_MASK);
m_MARK = registerFile.GetRegister32(STATE_REGS_MARK);
m_R[0] = registerFile.GetRegister32(STATE_REGS_ROW0);
m_R[1] = registerFile.GetRegister32(STATE_REGS_ROW1);
m_R[2] = registerFile.GetRegister32(STATE_REGS_ROW2);
m_R[3] = registerFile.GetRegister32(STATE_REGS_ROW3);
m_C[0] = registerFile.GetRegister32(STATE_REGS_COL0);
m_C[1] = registerFile.GetRegister32(STATE_REGS_COL1);
m_C[2] = registerFile.GetRegister32(STATE_REGS_COL2);
m_C[3] = registerFile.GetRegister32(STATE_REGS_COL3);
m_ITOP = registerFile.GetRegister32(STATE_REGS_ITOP);
m_ITOPS = registerFile.GetRegister32(STATE_REGS_ITOPS);
m_readTick = registerFile.GetRegister32(STATE_REGS_READTICK);
m_writeTick = registerFile.GetRegister32(STATE_REGS_WRITETICK);
m_fifoIndex = registerFile.GetRegister32(STATE_REGS_FIFOINDEX);
}
{
auto path = string_format(STATE_PATH_FIFO_FORMAT, m_number);
archive.BeginReadFile(path.c_str())->Read(&m_fifoBuffer, sizeof(m_fifoBuffer));
}
}
uint32 CVif::GetTOP() const
{
throw std::exception();
}
uint32 CVif::GetITOP() const
{
return m_ITOP;
}
uint32 CVif::ReceiveDMA(uint32 address, uint32 qwc, uint32 unused, bool tagIncluded)
{
if(m_STAT.nVEW && m_vpu.IsVuRunning())
{
//Is waiting for program end, don't bother
return 0;
}
#ifdef PROFILE
CProfilerZone profilerZone(m_vifProfilerZone);
#endif
#ifdef _DEBUG
CLog::GetInstance().Print(LOG_NAME, "vif%i : Processing packet @ 0x%0.8X, qwc = 0x%X, tagIncluded = %i\r\n",
m_number, address, qwc, static_cast<int>(tagIncluded));
#endif
m_stream.SetDmaParams(address, qwc * 0x10, tagIncluded);
ProcessPacket(m_stream);
uint32 remainingSize = m_stream.GetRemainingDmaTransferSize();
assert((remainingSize & 0x0F) == 0);
remainingSize /= 0x10;
return qwc - remainingSize;
}
bool CVif::IsWaitingForProgramEnd() const
{
return (m_STAT.nVEW != 0);
}
bool CVif::IsStalledByInterrupt() const
{
return (m_STAT.nVIS != 0);
}
void CVif::ProcessFifoWrite(uint32 address, uint32 value)
{
assert(m_fifoIndex != FIFO_SIZE);
if(m_fifoIndex == FIFO_SIZE)
{
return;
}
uint32 index = (address & 0xF) / 4;
*reinterpret_cast<uint32*>(m_fifoBuffer + m_fifoIndex + index * 4) = value;
if(index == 3)
{
m_fifoIndex += 0x10;
m_stream.SetFifoParams(m_fifoBuffer, m_fifoIndex);
ProcessPacket(m_stream);
uint32 newIndex = m_stream.GetRemainingDmaTransferSize();
uint32 discardSize = m_fifoIndex - newIndex;
memmove(m_fifoBuffer, m_fifoBuffer + discardSize, newIndex);
m_fifoIndex = newIndex;
}
}
void CVif::ProcessPacket(StreamType& stream)
{
while(stream.GetAvailableReadBytes())
{
if(m_STAT.nVPS == 1)
{
//Command is waiting for more data...
ExecuteCommand(stream, m_CODE);
if((m_STAT.nVPS == 1) && (stream.GetAvailableReadBytes() != 0))
{
//We have data in our FIFO but we still need more than what's available
break;
}
else
{
continue;
}
}
if(m_STAT.nVEW == 1)
{
if(m_vpu.IsVuRunning()) break;
m_STAT.nVEW = 0;
//Command is waiting for micro-program to end.
ExecuteCommand(stream, m_CODE);
continue;
}
#ifdef DELAYED_MSCAL
m_previousCODE = m_CODE;
#endif
if(m_STAT.nVIS)
{
//Should check for MARK command
break;
}
stream.Read(&m_CODE, sizeof(CODE));
if(m_CODE.nI != 0)
{
//Next command will be stalled
m_STAT.nVIS = 1;
m_STAT.nINT = 1;
}
m_NUM = m_CODE.nNUM;
ExecuteCommand(stream, m_CODE);
}
#ifdef DELAYED_MSCAL
if(stream.GetAvailableReadBytes() == 0)
{
ResumeDelayedMicroProgram();
}
#endif
}
void CVif::ExecuteCommand(StreamType& stream, CODE nCommand)
{
#ifdef _DEBUG
if(m_number == 0)
{
DisassembleCommand(nCommand);
}
#endif
if(nCommand.nCMD >= 0x60)
{
#ifdef DELAYED_MSCAL
//Check if previous cmd was MSCAL and if we have a pending MSCAL
if(m_previousCODE.nCMD == 0x14)
{
uint32 prevImm = m_pendingMicroProgram / 8;
if(ResumeDelayedMicroProgram())
{
assert(m_previousCODE.nIMM == prevImm);
m_previousCODE.nCMD = 0;
//Set waiting for microprogram bit to make sure we come back here and execute UNPACK
m_STAT.nVEW = 1;
return;
}
}
#endif
Cmd_UNPACK(stream, nCommand, (nCommand.nIMM & 0x03FF));
return;
}
switch(nCommand.nCMD)
{
case 0:
//NOP
break;
case 0x01:
//STCYCL
m_CYCLE <<= nCommand.nIMM;
break;
case 0x04:
#ifdef DELAYED_MSCAL
if(ResumeDelayedMicroProgram())
{
m_STAT.nVEW = 1;
return;
}
#endif
m_ITOPS = nCommand.nIMM & 0x3FF;
break;
case 0x05:
//STMOD
m_MODE = nCommand.nIMM & 0x03;
break;
case 0x07:
//MARK
m_MARK = nCommand.nIMM;
break;
case 0x10:
//FLUSHE
if(m_vpu.IsVuRunning())
{
m_STAT.nVEW = 1;
}
else
{
m_STAT.nVEW = 0;
}
break;
case 0x14:
//MSCAL
#ifdef DELAYED_MSCAL
if(ResumeDelayedMicroProgram())
{
m_STAT.nVEW = 1;
return;
}
StartDelayedMicroProgram(nCommand.nIMM * 8);
#else
StartMicroProgram(nCommand.nIMM * 8);
#endif
break;
case 0x15:
//MSCALF
//TODO: Wait for GIF PATH 1 and 2 transfers to be over
StartMicroProgram(nCommand.nIMM * 8);
break;
case 0x17:
//MSCNT
StartMicroProgram(m_vpu.GetContext().m_State.nPC);
break;
case 0x20:
//STMASK
Cmd_STMASK(stream, nCommand);
break;
case 0x30:
//STROW
Cmd_STROW(stream, nCommand);
break;
case 0x31:
//STCOL
Cmd_STCOL(stream, nCommand);
break;
case 0x4A:
//MPG
Cmd_MPG(stream, nCommand);
break;
default:
assert(0);
break;
}
}
void CVif::Cmd_MPG(StreamType& stream, CODE nCommand)
{
uint32 nSize = stream.GetAvailableReadBytes();
uint32 nNum = (m_NUM == 0) ? (256) : (m_NUM);
uint32 nCodeNum = (m_CODE.nNUM == 0) ? (256) : (m_CODE.nNUM);
uint32 nTransfered = (nCodeNum - nNum) * 8;
nCodeNum *= 8;
nNum *= 8;
nSize = std::min<uint32>(nNum, nSize);
uint32 nDstAddr = (m_CODE.nIMM * 8) + nTransfered;
//Check if microprogram is running
if(m_vpu.IsVuRunning())
{
m_STAT.nVEW = 1;
return;
}
if(nSize != 0)
{
uint8* microProgram = reinterpret_cast<uint8*>(alloca(nSize));
stream.Read(microProgram, nSize);
//Check if there's a change
auto microMem = m_vpu.GetMicroMemory();
if(memcmp(microMem + nDstAddr, microProgram, nSize) != 0)
{
m_vpu.InvalidateMicroProgram();
memcpy(microMem + nDstAddr, microProgram, nSize);
}
}
m_NUM -= static_cast<uint8>(nSize / 8);
if((m_NUM == 0) && (nSize != 0))
{
m_STAT.nVPS = 0;
}
else
{
m_STAT.nVPS = 1;
}
}
void CVif::Cmd_STROW(StreamType& stream, CODE nCommand)
{
if(m_NUM == 0)
{
m_NUM = 4;
}
while(m_NUM != 0 && stream.GetAvailableReadBytes())
{
assert(m_NUM <= 4);
stream.Read(&m_R[4 - m_NUM], 4);
m_NUM--;
}
if(m_NUM == 0)
{
m_STAT.nVPS = 0;
}
else
{
m_STAT.nVPS = 1;
}
}
void CVif::Cmd_STCOL(StreamType& stream, CODE nCommand)
{
if(m_NUM == 0)
{
m_NUM = 4;
}
while(m_NUM != 0 && stream.GetAvailableReadBytes())
{
assert(m_NUM <= 4);
stream.Read(&m_C[4 - m_NUM], 4);
m_NUM--;
}
if(m_NUM == 0)
{
m_STAT.nVPS = 0;
}
else
{
m_STAT.nVPS = 1;
}
}
void CVif::Cmd_STMASK(StreamType& stream, CODE command)
{
if(m_NUM == 0)
{
m_NUM = 1;
}
while(m_NUM != 0 && stream.GetAvailableReadBytes())
{
stream.Read(&m_MASK, 4);
m_NUM--;
}
if(m_NUM == 0)
{
m_STAT.nVPS = 0;
}
else
{
m_STAT.nVPS = 1;
}
}
void CVif::Cmd_UNPACK(StreamType& stream, CODE nCommand, uint32 nDstAddr)
{
assert((nCommand.nCMD & 0x60) == 0x60);
const auto vuMem = m_vpu.GetVuMemory();
const auto vuMemSize = m_vpu.GetVuMemorySize();
bool usn = (m_CODE.nIMM & 0x4000) != 0;
bool useMask = (nCommand.nCMD & 0x10) != 0;
uint32 cl = m_CYCLE.nCL;
uint32 wl = m_CYCLE.nWL;
if(wl == 0)
{
wl = UINT_MAX;
cl = UINT_MAX;
}
if(m_NUM == nCommand.nNUM)
{
m_readTick = 0;
m_writeTick = 0;
}
uint32 currentNum = (m_NUM == 0) ? 256 : m_NUM;
uint32 codeNum = (m_CODE.nNUM == 0) ? 256 : m_CODE.nNUM;
uint32 transfered = codeNum - currentNum;
if(cl > wl)
{
nDstAddr += cl * (transfered / wl) + (transfered % wl);
}
else
{
nDstAddr += transfered;
}
nDstAddr *= 0x10;
while(currentNum != 0)
{
bool mustWrite = false;
uint128 writeValue;
memset(&writeValue, 0, sizeof(writeValue));
if(cl >= wl)
{
if(m_readTick < wl || wl == 0)
{
bool success = Unpack_ReadValue(nCommand, stream, writeValue, usn);
if(!success) break;
mustWrite = true;
}
}
else
{
if(m_writeTick < cl)
{
bool success = Unpack_ReadValue(nCommand, stream, writeValue, usn);
if(!success) break;
}
mustWrite = true;
}
if(mustWrite)
{
auto dst = reinterpret_cast<uint128*>(vuMem + nDstAddr);
for(unsigned int i = 0; i < 4; i++)
{
uint32 maskOp = useMask ? GetMaskOp(i, m_writeTick) : MASK_DATA;
if(maskOp == MASK_DATA)
{
if(m_MODE == MODE_OFFSET)
{
writeValue.nV[i] += m_R[i];
}
else if(m_MODE == MODE_DIFFERENCE)
{
writeValue.nV[i] += m_R[i];
m_R[i] = writeValue.nV[i];
}
dst->nV[i] = writeValue.nV[i];
}
else if(maskOp == MASK_ROW)
{
dst->nV[i] = m_R[i];
}
else if(maskOp == MASK_COL)
{
int index = (m_writeTick > 3) ? 3 : m_writeTick;
dst->nV[i] = m_C[index];
}
else if(maskOp == MASK_MASK)
{
//Don't write anything
}
else
{
assert(0);
}
}
currentNum--;
}
if(cl >= wl)
{
m_writeTick = std::min<uint32>(m_writeTick + 1, wl);
m_readTick = std::min<uint32>(m_readTick + 1, cl);
if(m_readTick == cl)
{
m_writeTick = 0;
m_readTick = 0;
}
}
else
{
m_writeTick = std::min<uint32>(m_writeTick + 1, wl);
m_readTick = std::min<uint32>(m_readTick + 1, cl);
if(m_writeTick == wl)
{
m_writeTick = 0;
m_readTick = 0;
}
}
nDstAddr += 0x10;
nDstAddr &= (vuMemSize - 1);
}
if(currentNum != 0)
{
m_STAT.nVPS = 1;
}
else
{
stream.Align32();
m_STAT.nVPS = 0;
}
m_NUM = static_cast<uint8>(currentNum);
}
bool CVif::Unpack_ReadValue(const CODE& nCommand, StreamType& stream, uint128& writeValue, bool usn)
{
bool success = false;
switch(nCommand.nCMD & 0x0F)
{
case 0x00:
//S-32
success = Unpack_S32(stream, writeValue);
break;
case 0x01:
//S-16
success = Unpack_S16(stream, writeValue, usn);
break;
case 0x02:
//S-8
success = Unpack_S8(stream, writeValue, usn);
break;
case 0x04:
//V2-32
success = Unpack_V32(stream, writeValue, 2);
break;
case 0x05:
//V2-16
success = Unpack_V16(stream, writeValue, 2, usn);
break;
case 0x06:
//V2-8
success = Unpack_V8(stream, writeValue, 2, usn);
break;
case 0x08:
//V3-32
success = Unpack_V32(stream, writeValue, 3);
break;
case 0x09:
//V3-16
success = Unpack_V16(stream, writeValue, 3, usn);
break;
case 0x0A:
//V3-8
success = Unpack_V8(stream, writeValue, 3, usn);
break;
case 0x0C:
//V4-32
success = Unpack_V32(stream, writeValue, 4);
break;
case 0x0D:
//V4-16
success = Unpack_V16(stream, writeValue, 4, usn);
break;
case 0x0E:
//V4-8
success = Unpack_V8(stream, writeValue, 4, usn);
break;
case 0x0F:
//V4-5
success = Unpack_V45(stream, writeValue);
break;
default:
assert(0);
break;
}
return success;
}
bool CVif::Unpack_S32(StreamType& stream, uint128& result)
{
if(stream.GetAvailableReadBytes() < 4) return false;
uint32 word = 0;
stream.Read(&word, 4);
for(unsigned int i = 0; i < 4; i++)
{
result.nV[i] = word;
}
return true;
}
bool CVif::Unpack_S16(StreamType& stream, uint128& result, bool zeroExtend)
{
if(stream.GetAvailableReadBytes() < 2) return false;
uint32 temp = 0;
stream.Read(&temp, 2);
if(!zeroExtend)
{
temp = static_cast<int16>(temp);
}
for(unsigned int i = 0; i < 4; i++)
{
result.nV[i] = temp;
}
return true;
}
bool CVif::Unpack_S8(StreamType& stream, uint128& result, bool zeroExtend)
{
if(stream.GetAvailableReadBytes() < 1) return false;
uint32 temp = 0;
stream.Read(&temp, 1);
if(!zeroExtend)
{
temp = static_cast<int8>(temp);
}
for(unsigned int i = 0; i < 4; i++)
{
result.nV[i] = temp;
}
return true;
}
bool CVif::Unpack_V8(StreamType& stream, uint128& result, unsigned int fields, bool zeroExtend)
{
if(stream.GetAvailableReadBytes() < (fields)) return false;
for(unsigned int i = 0; i < fields; i++)
{
uint32 temp = 0;
stream.Read(&temp, 1);
if(!zeroExtend)
{
temp = static_cast<int8>(temp);
}
result.nV[i] = temp;
}
return true;
}
bool CVif::Unpack_V16(StreamType& stream, uint128& result, unsigned int fields, bool zeroExtend)
{
if(stream.GetAvailableReadBytes() < (fields * 2)) return false;
for(unsigned int i = 0; i < fields; i++)
{
uint32 temp = 0;
stream.Read(&temp, 2);
if(!zeroExtend)
{
temp = static_cast<int16>(temp);
}
result.nV[i] = temp;
}
return true;
}
bool CVif::Unpack_V32(StreamType& stream, uint128& result, unsigned int fields)
{
if(stream.GetAvailableReadBytes() < (fields * 4)) return false;
stream.Read(&result, (fields * 4));
return true;
}
bool CVif::Unpack_V45(StreamType& stream, uint128& result)
{
if(stream.GetAvailableReadBytes() < 2) return false;
uint16 nColor = 0;
stream.Read(&nColor, 2);
result.nV0 = ((nColor >> 0) & 0x1F) << 3;
result.nV1 = ((nColor >> 5) & 0x1F) << 3;
result.nV2 = ((nColor >> 10) & 0x1F) << 3;
result.nV3 = ((nColor >> 15) & 0x01) << 7;
return true;
}
uint32 CVif::GetMaskOp(unsigned int row, unsigned int col) const
{
if(col > 3) col = 3;
assert(row < 4);
unsigned int index = (col * 4) + row;
return (m_MASK >> (index * 2)) & 0x03;
}
void CVif::PrepareMicroProgram()
{
m_ITOP = m_ITOPS;
}
void CVif::StartMicroProgram(uint32 address)
{
if(m_vpu.IsVuRunning())
{
m_STAT.nVEW = 1;
return;
}
assert(!m_STAT.nVEW);
PrepareMicroProgram();
m_vpu.ExecuteMicroProgram(address);
}
#ifdef DELAYED_MSCAL
void CVif::StartDelayedMicroProgram(uint32 address)
{
if(m_vpu.IsVuRunning())
{
m_STAT.nVEW = 1;
return;
}
assert(!m_STAT.nVEW);
PrepareMicroProgram();
m_pendingMicroProgram = address;
}
bool CVif::ResumeDelayedMicroProgram()
{
if(m_pendingMicroProgram != -1)
{
assert(!IsWaitingForProgramEnd());
assert(!m_vpu.IsVuRunning());
m_vpu.ExecuteMicroProgram(m_pendingMicroProgram);
m_pendingMicroProgram = -1;
return true;
}
else
{
return false;
}
}
#endif
void CVif::DisassembleGet(uint32 address)
{
switch(address)
{
case VIF0_MARK:
CLog::GetInstance().Print(LOG_NAME, "VIF0_MARK.\r\n");
break;
case VIF0_CYCLE:
CLog::GetInstance().Print(LOG_NAME, "VIF0_CYCLE.\r\n");
break;
case VIF0_MODE:
CLog::GetInstance().Print(LOG_NAME, "VIF0_MODE.\r\n");
break;
case VIF0_R0:
CLog::GetInstance().Print(LOG_NAME, "VIF0_R0.\r\n");
break;
case VIF0_R1:
CLog::GetInstance().Print(LOG_NAME, "VIF0_R1.\r\n");
break;
case VIF0_R2:
CLog::GetInstance().Print(LOG_NAME, "VIF0_R2.\r\n");
break;
case VIF0_R3:
CLog::GetInstance().Print(LOG_NAME, "VIF0_R3.\r\n");
break;
case VIF1_MARK:
CLog::GetInstance().Print(LOG_NAME, "VIF1_MARK.\r\n");
break;
case VIF1_CYCLE:
CLog::GetInstance().Print(LOG_NAME, "VIF1_CYCLE.\r\n");
break;
case VIF1_MODE:
CLog::GetInstance().Print(LOG_NAME, "VIF1_MODE.\r\n");
break;
case VIF1_R0:
CLog::GetInstance().Print(LOG_NAME, "VIF1_R0.\r\n");
break;
case VIF1_R1:
CLog::GetInstance().Print(LOG_NAME, "VIF1_R1.\r\n");
break;
case VIF1_R2:
CLog::GetInstance().Print(LOG_NAME, "VIF1_R2.\r\n");
break;
case VIF1_R3:
CLog::GetInstance().Print(LOG_NAME, "VIF1_R3.\r\n");
break;
default:
CLog::GetInstance().Print(LOG_NAME, "Reading unknown register 0x%0.8X.\r\n", address);
break;
}
}
void CVif::DisassembleSet(uint32 address, uint32 value)
{
if((address >= VIF0_FIFO_START) && (address < VIF0_FIFO_END))
{
CLog::GetInstance().Print(LOG_NAME, "VIF0_FIFO(0x%0.3X) = 0x%0.8X.\r\n", address & 0xFFF, value);
}
else if((address >= VIF1_FIFO_START) && (address < VIF1_FIFO_END))
{
CLog::GetInstance().Print(LOG_NAME, "VIF1_FIFO(0x%0.3X) = 0x%0.8X.\r\n", address & 0xFFF, value);
}
else
{
switch(address)
{
case VIF1_FBRST:
CLog::GetInstance().Print(LOG_NAME, "VIF1_FBRST = 0x%0.8X.\r\n", value);
break;
case VIF0_MARK:
CLog::GetInstance().Print(LOG_NAME, "VIF0_MARK = 0x%0.8X.\r\n", value);
break;
case VIF1_MARK:
CLog::GetInstance().Print(LOG_NAME, "VIF1_MARK = 0x%0.8X.\r\n", value);
break;
default:
CLog::GetInstance().Print(LOG_NAME, "Writing unknown register 0x%0.8X, 0x%0.8X.\r\n", address, value);
break;
}
}
}
void CVif::DisassembleCommand(CODE code)
{
if(m_STAT.nVPS != 0) return;
CLog::GetInstance().Print(LOG_NAME, "vif%i : ", m_number);
if(code.nI)
{
CLog::GetInstance().Print(LOG_NAME, "(I) ");
}
if(code.nCMD >= 0x60)
{
const char* packFormats[16] =
{
"S-32",
"S-16",
"S-8",
"(Unknown)",
"V2-32",
"V2-16",
"V2-8",
"(Unknown)",
"V3-32",
"V3-16",
"V3-8",
"(Unknown)",
"V4-32",
"V4-16",
"V4-8",
"V4-5"
};
CLog::GetInstance().Print(LOG_NAME, "UNPACK(format = %s, imm = 0x%x, num = 0x%x);\r\n",
packFormats[code.nCMD & 0x0F], code.nIMM, code.nNUM);
}
else
{
switch(code.nCMD)
{
case 0x00:
CLog::GetInstance().Print(LOG_NAME, "NOP\r\n");
break;
case 0x01:
CLog::GetInstance().Print(LOG_NAME, "STCYCL(imm = 0x%x);\r\n", code.nIMM);
break;
case 0x02:
CLog::GetInstance().Print(LOG_NAME, "OFFSET(imm = 0x%x);\r\n", code.nIMM);
break;
case 0x03:
CLog::GetInstance().Print(LOG_NAME, "BASE(imm = 0x%x);\r\n", code.nIMM);
break;
case 0x04:
CLog::GetInstance().Print(LOG_NAME, "ITOP(imm = 0x%x);\r\n", code.nIMM);
break;
case 0x05:
CLog::GetInstance().Print(LOG_NAME, "STMOD(imm = 0x%x);\r\n", code.nIMM);
break;
case 0x06:
CLog::GetInstance().Print(LOG_NAME, "MSKPATH3();\r\n");
break;
case 0x07:
CLog::GetInstance().Print(LOG_NAME, "MARK(imm = 0x%x);\r\n", code.nIMM);
break;
case 0x10:
CLog::GetInstance().Print(LOG_NAME, "FLUSHE();\r\n");
break;
case 0x11:
CLog::GetInstance().Print(LOG_NAME, "FLUSH();\r\n");
break;
case 0x13:
CLog::GetInstance().Print(LOG_NAME, "FLUSHA();\r\n");
break;
case 0x14:
CLog::GetInstance().Print(LOG_NAME, "MSCAL(imm = 0x%x);\r\n", code.nIMM);
break;
case 0x15:
CLog::GetInstance().Print(LOG_NAME, "MSCALF(imm = 0x%x);\r\n", code.nIMM);
break;
case 0x17:
CLog::GetInstance().Print(LOG_NAME, "MSCNT();\r\n");
break;
case 0x20:
CLog::GetInstance().Print(LOG_NAME, "STMASK();\r\n");
break;
case 0x30:
CLog::GetInstance().Print(LOG_NAME, "STROW();\r\n");
break;
case 0x31:
CLog::GetInstance().Print(LOG_NAME, "STCOL();\r\n");
break;
case 0x4A:
CLog::GetInstance().Print(LOG_NAME, "MPG(imm = 0x%x, num = 0x%x);\r\n", code.nIMM, code.nNUM);
break;
case 0x50:
CLog::GetInstance().Print(LOG_NAME, "DIRECT(imm = 0x%x);\r\n", code.nIMM);
break;
case 0x51:
CLog::GetInstance().Print(LOG_NAME, "DIRECTHL(imm = 0x%x);\r\n", code.nIMM);
break;
default:
CLog::GetInstance().Print(LOG_NAME, "Unknown command (0x%x).\r\n", code.nCMD);
break;
}
}
}
//CFifoStream
//--------------------------------------------------
CVif::CFifoStream::CFifoStream(uint8* ram, uint8* spr)
: m_ram(ram)
, m_spr(spr)
{
}
CVif::CFifoStream::~CFifoStream()
{
}
void CVif::CFifoStream::Reset()
{
m_bufferPosition = BUFFERSIZE;
m_nextAddress = 0;
m_endAddress = 0;
m_tagIncluded = false;
m_source = nullptr;
}
void CVif::CFifoStream::Read(void* buffer, uint32 size)
{
assert(m_source != NULL);
uint8* readBuffer = reinterpret_cast<uint8*>(buffer);
while(size != 0)
{
SyncBuffer();
uint32 read = std::min<uint32>(size, BUFFERSIZE - m_bufferPosition);
if(readBuffer != NULL)
{
memcpy(readBuffer, reinterpret_cast<uint8*>(&m_buffer) + m_bufferPosition, read);
readBuffer += read;
}
m_bufferPosition += read;
size -= read;
}
}
void CVif::CFifoStream::Flush()
{
m_bufferPosition = BUFFERSIZE;
}
void CVif::CFifoStream::SetDmaParams(uint32 address, uint32 size, bool tagIncluded)
{
if(address & 0x80000000)
{
m_source = m_spr;
address &= (PS2::EE_SPR_SIZE - 1);
assert((address + size) <= PS2::EE_SPR_SIZE);
}
else
{
m_source = m_ram;
address &= (PS2::EE_RAM_SIZE - 1);
assert((address + size) <= PS2::EE_RAM_SIZE);
}
m_nextAddress = address;
m_endAddress = address + size;
m_tagIncluded = tagIncluded;
SyncBuffer();
}
void CVif::CFifoStream::SetFifoParams(uint8* source, uint32 size)
{
m_source = source;
m_nextAddress = 0;
m_endAddress = size;
m_tagIncluded = false;
SyncBuffer();
}
uint32 CVif::CFifoStream::GetAvailableReadBytes() const
{
return GetRemainingDmaTransferSize() + (BUFFERSIZE - m_bufferPosition);
}
uint32 CVif::CFifoStream::GetRemainingDmaTransferSize() const
{
return m_endAddress - m_nextAddress;
}
void CVif::CFifoStream::Align32()
{
unsigned int remainBytes = m_bufferPosition & 0x03;
if(remainBytes == 0) return;
Read(NULL, 4 - remainBytes);
assert((m_bufferPosition & 0x03) == 0);
}
void CVif::CFifoStream::SyncBuffer()
{
assert(m_bufferPosition <= BUFFERSIZE);
if(m_bufferPosition >= BUFFERSIZE)
{
if(m_nextAddress >= m_endAddress)
{
throw std::exception();
}
m_buffer = *reinterpret_cast<uint128*>(&m_source[m_nextAddress]);
m_nextAddress += 0x10;
m_bufferPosition = 0;
if(m_tagIncluded)
{
//Skip next 8 bytes
m_tagIncluded = false;
m_bufferPosition += 8;
}
}
}