void CVPU1::Cmd_DIRECT(StreamType& stream, CODE nCommand) { uint32 nSize = stream.GetAvailableReadBytes(); nSize = std::min<uint32>(m_CODE.nIMM * 0x10, nSize); assert((nSize & 0x0F) == 0); if(nSize != 0) { uint8* packet = reinterpret_cast<uint8*>(alloca(nSize)); stream.Read(packet, nSize); int32 remainingLength = nSize; while(remainingLength > 0) { uint32 processed = m_vif.GetGif().ProcessPacket(packet, 0, remainingLength, CGsPacketMetadata(2)); packet += processed; remainingLength -= processed; assert(remainingLength >= 0); } } m_CODE.nIMM -= (nSize / 0x10); if((m_CODE.nIMM == 0) && (nSize != 0)) { m_STAT.nVPS = 0; } else { m_STAT.nVPS = 1; } }
void CVPU::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(IsRunning()) 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 stream.Read(&m_CODE, sizeof(CODE)); assert(m_CODE.nI == 0); m_NUM = m_CODE.nNUM; ExecuteCommand(stream, m_CODE); } #ifdef DELAYED_MSCAL if(stream.GetAvailableReadBytes() == 0) { ResumeDelayedMicroProgram(); } #endif }
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; }
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; }
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 = std::min<uint32>(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_microMem + nDstAddr, microProgram, nSize) != 0) { m_executor.ClearActiveBlocks(); memcpy(m_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; } }
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_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; }
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_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 CVif1::Cmd_DIRECT(StreamType& stream, CODE nCommand) { uint32 nSize = stream.GetAvailableReadBytes(); nSize = std::min<uint32>(m_CODE.nIMM * 0x10, nSize); assert((nSize & 0x0F) == 0); if(nSize != 0) { if(m_directBuffer.size() < nSize) { m_directBuffer.resize(nSize); } auto packet = m_directBuffer.data(); stream.Read(packet, nSize); int32 remainingLength = nSize; while(remainingLength > 0) { uint32 processed = m_gif.ProcessPacket(packet, 0, remainingLength, CGsPacketMetadata(2)); packet += processed; remainingLength -= processed; assert(remainingLength >= 0); } } m_CODE.nIMM -= (nSize / 0x10); if((m_CODE.nIMM == 0) && (nSize != 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; } uint32 currentNum = (m_NUM == 0) ? 256 : m_NUM; uint32 codeNum = (m_CODE.nNUM == 0) ? 256 : m_CODE.nNUM; uint32 transfered = codeNum - currentNum; assert(transfered == 0 || cl == wl); //The value above is only valid for specific combinations of cl and wl nDstAddr += transfered; nDstAddr *= 0x10; uint128* dst = reinterpret_cast<uint128*>(&m_vuMem[nDstAddr]); while((currentNum != 0) && stream.GetAvailableReadBytes()) { 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) { 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_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; } } dst++; } if(currentNum != 0) { m_STAT.nVPS = 1; } else { // assert((m_cmdBuffer.GetReadCount() & 0x03) == 0); stream.Align32(); m_STAT.nVPS = 0; } m_NUM = static_cast<uint8>(currentNum); }