mirror of
https://github.com/jpd002/Play-.git
synced 2025-04-28 21:57:57 +03:00
823 lines
20 KiB
C++
823 lines
20 KiB
C++
#include "VPU.h"
|
|
#include "Log.h"
|
|
#include "RegisterStateFile.h"
|
|
#include <boost/lexical_cast.hpp>
|
|
|
|
using namespace Framework;
|
|
using namespace boost;
|
|
using namespace std;
|
|
using namespace std::tr1;
|
|
|
|
#define LOG_NAME ("vpu")
|
|
|
|
#define STATE_PREFIX ("vif/vpu_")
|
|
#define STATE_SUFFIX (".xml")
|
|
#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_ITOP ("ITOP")
|
|
#define STATE_REGS_ITOPS ("ITOPS")
|
|
#define STATE_REGS_READTICK ("readTick")
|
|
#define STATE_REGS_WRITETICK ("writeTick")
|
|
|
|
CVPU::CVPU(CVIF& vif, unsigned int vpuNumber, const CVIF::VPUINIT& vpuInit) :
|
|
m_vif(vif),
|
|
m_vpuNumber(vpuNumber),
|
|
m_pMicroMem(vpuInit.microMem),
|
|
m_pVUMem(vpuInit.vuMem),
|
|
m_pCtx(vpuInit.context),
|
|
m_execThread(NULL),
|
|
m_endThread(false),
|
|
m_executor(*vpuInit.context),
|
|
m_paused(true)
|
|
{
|
|
// m_execThread = new thread(bind(&CVPU::ExecuteThreadProc, this));
|
|
// m_execThread = new thread(bind(&CVPU::CommandThreadProc, this));
|
|
}
|
|
|
|
CVPU::~CVPU()
|
|
{
|
|
if(m_execThread != NULL)
|
|
{
|
|
JoinThread();
|
|
}
|
|
}
|
|
|
|
void CVPU::JoinThread()
|
|
{
|
|
if(m_execThread != NULL)
|
|
{
|
|
m_endThread = true;
|
|
#ifdef _DEBUG
|
|
m_execDoneCondition.notify_all();
|
|
#endif
|
|
m_execThread->join();
|
|
delete m_execThread;
|
|
m_execThread = NULL;
|
|
}
|
|
}
|
|
|
|
void CVPU::SingleStep()
|
|
{
|
|
mutex::scoped_lock lock(m_execMutex);
|
|
m_paused = false;
|
|
#ifdef _DEBUG
|
|
m_execDoneCondition.wait(m_execMutex);
|
|
#endif
|
|
}
|
|
|
|
void CVPU::Reset()
|
|
{
|
|
m_executor.Clear();
|
|
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));
|
|
m_MODE = 0;
|
|
m_NUM = 0;
|
|
m_MASK = 0;
|
|
m_ITOP = 0;
|
|
m_ITOPS = 0;
|
|
}
|
|
|
|
void CVPU::SaveState(CZipArchiveWriter& archive)
|
|
{
|
|
string path = STATE_PREFIX + lexical_cast<string>(m_vpuNumber) + STATE_SUFFIX;
|
|
CRegisterStateFile* 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_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_ITOP, m_ITOP);
|
|
registerFile->SetRegister32(STATE_REGS_ITOPS, m_ITOPS);
|
|
registerFile->SetRegister32(STATE_REGS_READTICK, m_readTick);
|
|
registerFile->SetRegister32(STATE_REGS_WRITETICK, m_writeTick);
|
|
archive.InsertFile(registerFile);
|
|
}
|
|
|
|
void CVPU::LoadState(CZipArchiveReader& archive)
|
|
{
|
|
string path = STATE_PREFIX + lexical_cast<string>(m_vpuNumber) + STATE_SUFFIX;
|
|
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_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_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);
|
|
}
|
|
|
|
uint32 CVPU::GetTOP() const
|
|
{
|
|
throw exception();
|
|
}
|
|
|
|
uint32 CVPU::GetITOP() const
|
|
{
|
|
return m_ITOP;
|
|
}
|
|
|
|
uint8* CVPU::GetVuMemory() const
|
|
{
|
|
return m_pVUMem;
|
|
}
|
|
|
|
CMIPS& CVPU::GetContext() const
|
|
{
|
|
return *m_pCtx;
|
|
}
|
|
|
|
void CVPU::ProcessPacket(StreamType& stream)
|
|
{
|
|
while(stream.GetAvailableReadBytes())
|
|
{
|
|
if(m_STAT.nVPS == 1)
|
|
{
|
|
//Command is waiting for more data...
|
|
ExecuteCommand(stream, m_CODE);
|
|
continue;
|
|
}
|
|
if(m_STAT.nVEW == 1)
|
|
{
|
|
//Command is waiting for micro-program to end.
|
|
ExecuteCommand(stream, m_CODE);
|
|
if(m_STAT.nVEW == 1)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
stream.Read(&m_CODE, sizeof(CODE));
|
|
|
|
assert(m_CODE.nI == 0);
|
|
|
|
m_NUM = m_CODE.nNUM;
|
|
|
|
ExecuteCommand(stream, m_CODE);
|
|
}
|
|
}
|
|
|
|
void CVPU::ExecuteCommand(StreamType& stream, CODE nCommand)
|
|
{
|
|
#ifdef _DEBUG
|
|
if(m_vpuNumber == 0)
|
|
{
|
|
DisassembleCommand(nCommand);
|
|
}
|
|
#endif
|
|
if(nCommand.nCMD >= 0x60)
|
|
{
|
|
return Cmd_UNPACK(stream, nCommand, (nCommand.nIMM & 0x03FF));
|
|
}
|
|
switch(nCommand.nCMD)
|
|
{
|
|
case 0:
|
|
//NOP
|
|
break;
|
|
case 0x01:
|
|
//STCYCL
|
|
m_CYCLE <<= nCommand.nIMM;
|
|
break;
|
|
case 0x04:
|
|
m_ITOPS = nCommand.nIMM & 0x3FF;
|
|
break;
|
|
case 0x05:
|
|
//STMOD
|
|
m_MODE = nCommand.nIMM & 0x03;
|
|
break;
|
|
case 0x14:
|
|
//MSCAL
|
|
StartMicroProgram(nCommand.nIMM * 8);
|
|
break;
|
|
case 0x17:
|
|
//MSCNT
|
|
StartMicroProgram(m_pCtx->m_State.nPC);
|
|
break;
|
|
case 0x20:
|
|
//STMASK
|
|
return Cmd_STMASK(stream, nCommand);
|
|
break;
|
|
case 0x30:
|
|
//STROW
|
|
return Cmd_STROW(stream, nCommand);
|
|
break;
|
|
case 0x4A:
|
|
//MPG
|
|
return Cmd_MPG(stream, nCommand);
|
|
break;
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CVPU::StartMicroProgram(uint32 address)
|
|
{
|
|
if(IsRunning())
|
|
{
|
|
m_STAT.nVEW = 1;
|
|
return;
|
|
}
|
|
|
|
assert(!m_STAT.nVEW);
|
|
|
|
ExecuteMicro(address);
|
|
}
|
|
|
|
void CVPU::ExecuteMicro(uint32 nAddress)
|
|
{
|
|
m_ITOP = m_ITOPS;
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Starting microprogram execution at 0x%0.8X.\r\n", nAddress);
|
|
|
|
m_pCtx->m_State.nPC = nAddress;
|
|
m_paused = true;
|
|
|
|
{
|
|
while(1)
|
|
{
|
|
unsigned int quota = 5000;
|
|
m_pCtx->m_State.nHasException = 0;
|
|
m_executor.Execute(quota);
|
|
if(m_pCtx->m_State.nHasException)
|
|
{
|
|
//E bit encountered
|
|
break;
|
|
// m_vif.SetStat(m_vif.GetStat() & ~GetVbs());
|
|
}
|
|
}
|
|
}
|
|
|
|
// m_vif.SetStat(m_vif.GetStat() | GetVbs());
|
|
// m_STAT.nVEW = 0;
|
|
}
|
|
/*
|
|
void CVPU::CommandThreadProc()
|
|
{
|
|
bool isDebuggingEnabled = m_vpuNumber == 0 ? m_vif.IsVu0DebuggingEnabled() : m_vif.IsVu1DebuggingEnabled();
|
|
const int bufferSize = 2345;
|
|
uint8* readBuffer = reinterpret_cast<uint8*>(alloca(bufferSize));
|
|
while(!m_endThread)
|
|
{
|
|
if(m_cmdBuffer.IsEmpty() && !IsRunning())
|
|
{
|
|
m_cmdBuffer.WaitForNotEmpty(1);
|
|
}
|
|
else
|
|
{
|
|
if(IsRunning())
|
|
{
|
|
unsigned int quota = isDebuggingEnabled ? 1 : 5000;
|
|
m_pCtx->m_State.nHasException = 0;
|
|
m_executor.Execute(quota);
|
|
if(m_pCtx->m_State.nHasException)
|
|
{
|
|
//E bit encountered
|
|
m_vif.SetStat(m_vif.GetStat() & ~GetVbs());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ProcessPacket();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
void CVPU::ExecuteThreadProc()
|
|
{
|
|
bool isDebuggingEnabled = m_vpuNumber == 0 ? m_vif.IsVu0DebuggingEnabled() : m_vif.IsVu1DebuggingEnabled();
|
|
unsigned int quota = isDebuggingEnabled ? 1 : 5000;
|
|
while(!m_endThread)
|
|
{
|
|
if(
|
|
!(m_vif.GetStat() & GetVbs()) ||
|
|
#ifdef _DEBUG
|
|
(m_paused && isDebuggingEnabled)
|
|
#else
|
|
false
|
|
#endif
|
|
)
|
|
{
|
|
mutex::scoped_lock execLock(m_execMutex);
|
|
xtime xt;
|
|
xtime_get(&xt, boost::TIME_UTC);
|
|
xt.nsec += 16 * 1000000;
|
|
m_execCondition.timed_wait(m_execMutex, xt);
|
|
// thread::sleep(xt);
|
|
// thread::yield();
|
|
}
|
|
else
|
|
{
|
|
// m_pCtx->m_State.nHasException = 0;
|
|
// m_executor.Execute(quota);
|
|
// if(m_pCtx->m_State.nHasException)
|
|
{
|
|
//E bit encountered
|
|
m_vif.SetStat(m_vif.GetStat() & ~GetVbs());
|
|
}
|
|
#ifdef _DEBUG
|
|
// if(m_executor.MustBreak())
|
|
{
|
|
m_paused = true;
|
|
m_execDoneCondition.notify_one();
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
void CVPU::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 = min(nNum, nSize);
|
|
|
|
uint32 nDstAddr = (m_CODE.nIMM * 8) + nTransfered;
|
|
|
|
//Check if microprogram is running
|
|
if(IsRunning())
|
|
{
|
|
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
|
|
if(memcmp(m_pMicroMem + nDstAddr, microProgram, nSize) != 0)
|
|
{
|
|
m_executor.Clear();
|
|
memcpy(m_pMicroMem + 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;
|
|
}
|
|
|
|
// return nSize;
|
|
}
|
|
|
|
void CVPU::Cmd_STROW(StreamType& stream, CODE nCommand)
|
|
{
|
|
if(m_NUM == 0)
|
|
{
|
|
m_NUM = 4;
|
|
}
|
|
|
|
// uint32 transfered = 0;
|
|
while(m_NUM != 0 && stream.GetAvailableReadBytes())
|
|
{
|
|
assert(m_NUM <= 4);
|
|
stream.Read(&m_R[4 - m_NUM], 4);
|
|
m_NUM--;
|
|
// transfered += 4;
|
|
}
|
|
|
|
if(m_NUM == 0)
|
|
{
|
|
m_STAT.nVPS = 0;
|
|
}
|
|
else
|
|
{
|
|
m_STAT.nVPS = 1;
|
|
}
|
|
|
|
// return transfered;
|
|
}
|
|
|
|
void CVPU::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 CVPU::Cmd_UNPACK(StreamType& stream, CODE nCommand, uint32 nDstAddr)
|
|
{
|
|
assert((nCommand.nCMD & 0x60) == 0x60);
|
|
|
|
bool usn = (m_CODE.nIMM & 0x4000) != 0;
|
|
bool useMask = (nCommand.nCMD & 0x10) != 0;
|
|
uint32 cl = m_CYCLE.nCL;
|
|
uint32 wl = m_CYCLE.nWL;
|
|
|
|
if(m_NUM == nCommand.nNUM)
|
|
{
|
|
m_readTick = 0;
|
|
m_writeTick = 0;
|
|
}
|
|
|
|
// assert(m_NUM == nCommand.nNUM);
|
|
// uint32 nTransfered = m_CODE.nNUM - m_NUM;
|
|
// nDstAddr += nTransfered;
|
|
|
|
nDstAddr *= 0x10;
|
|
|
|
uint128* dst = reinterpret_cast<uint128*>(&m_pVUMem[nDstAddr]);
|
|
|
|
//REMOVE
|
|
/*
|
|
uint32 address = stream.GetAddress();
|
|
uint128* src = reinterpret_cast<uint128*>(&stream.m_ram[address]);
|
|
uint32 toRead = min<uint32>(stream.GetAvailableReadBytes() / 0x10, m_NUM);
|
|
for(unsigned int i = 0; i < toRead; i++)
|
|
{
|
|
(*dst) = (*src);
|
|
dst += cl;
|
|
src += 1;
|
|
}
|
|
// uint32 toRead = min<uint32>(stream.GetSize() / 0x10, m_NUM);
|
|
stream.Read(NULL, toRead * 0x10);
|
|
m_NUM -= toRead;
|
|
*/
|
|
|
|
//REMOVE
|
|
while(m_NUM != 0 && stream.GetAvailableReadBytes())
|
|
{
|
|
bool mustWrite = false;
|
|
uint128 writeValue;
|
|
|
|
if(cl >= wl)
|
|
{
|
|
if(m_writeTick != wl || wl == 0)
|
|
{
|
|
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 0x05:
|
|
//V2-16
|
|
success = Unpack_V16(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 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;
|
|
}
|
|
|
|
if(!success) break;
|
|
mustWrite = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
assert(0);
|
|
}
|
|
|
|
if(mustWrite)
|
|
{
|
|
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)
|
|
{
|
|
assert(0);
|
|
}
|
|
|
|
dst->nV[i] = writeValue.nV[i];
|
|
}
|
|
else if(maskOp == MASK_MASK)
|
|
{
|
|
|
|
}
|
|
else
|
|
{
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
m_NUM--;
|
|
}
|
|
|
|
m_writeTick = min<uint32>(m_writeTick + 1, wl);
|
|
m_readTick = min<uint32>(m_readTick + 1, cl);
|
|
|
|
if(m_writeTick == wl && m_readTick == cl)
|
|
{
|
|
m_writeTick = 0;
|
|
m_readTick = 0;
|
|
}
|
|
|
|
dst++;
|
|
}
|
|
|
|
if(m_NUM != 0)
|
|
{
|
|
m_STAT.nVPS = 1;
|
|
}
|
|
else
|
|
{
|
|
// assert((m_cmdBuffer.GetReadCount() & 0x03) == 0);
|
|
stream.Align32();
|
|
m_STAT.nVPS = 0;
|
|
}
|
|
// return 0;
|
|
}
|
|
|
|
bool CVPU::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 CVPU::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 CVPU::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 CVPU::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 CVPU::Unpack_V32(StreamType& stream, uint128& result, unsigned int fields)
|
|
{
|
|
if(stream.GetAvailableReadBytes() < (fields * 4)) return false;
|
|
|
|
stream.Read(&result, (fields * 4));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CVPU::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 CVPU::GetVbs() const
|
|
{
|
|
switch(m_vpuNumber)
|
|
{
|
|
case 0:
|
|
return CVIF::STAT_VBS0;
|
|
case 1:
|
|
return CVIF::STAT_VBS1;
|
|
default:
|
|
throw exception();
|
|
}
|
|
}
|
|
|
|
bool CVPU::IsRunning() const
|
|
{
|
|
return (m_vif.GetStat() & GetVbs()) != 0;
|
|
}
|
|
|
|
uint32 CVPU::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 CVPU::DisassembleCommand(CODE code)
|
|
{
|
|
if(m_STAT.nVPS != 0) return;
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "vpu%i : ", m_vpuNumber);
|
|
|
|
if(code.nI)
|
|
{
|
|
CLog::GetInstance().Print(LOG_NAME, "(I) ");
|
|
}
|
|
|
|
if(code.nCMD >= 0x60)
|
|
{
|
|
const char* packFormats[16] =
|
|
{
|
|
"S-32",
|
|
"S-16",
|
|
"(Unknown)",
|
|
"(Unknown)",
|
|
"(Unknown)",
|
|
"V2-16",
|
|
"(Unknown)",
|
|
"(Unknown)",
|
|
"V3-32",
|
|
"V3-16",
|
|
"(Unknown)",
|
|
"(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, "STMODE(imm = 0x%x);\r\n", code.nIMM);
|
|
break;
|
|
case 0x06:
|
|
CLog::GetInstance().Print(LOG_NAME, "MSKPATH3();\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 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 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, num = 0x%x);\r\n", code.nIMM, code.nNUM);
|
|
break;
|
|
case 0x51:
|
|
CLog::GetInstance().Print(LOG_NAME, "DIRECTHL(imm = 0x%x, num = 0x%x);\r\n", code.nIMM, code.nNUM);
|
|
break;
|
|
default:
|
|
CLog::GetInstance().Print(LOG_NAME, "Unknown command (0x%x).\r\n", code.nCMD);
|
|
break;
|
|
}
|
|
}
|
|
}
|