CPU::State FifoPlayer::AdvanceFrame() { if (m_CurrentFrame >= m_FrameRangeEnd) { if (!m_Loop) return CPU::State::PowerDown; // If there are zero frames in the range then sleep instead of busy spinning if (m_FrameRangeStart >= m_FrameRangeEnd) return CPU::State::Stepping; // When looping, reload the contents of all the BP/CP/CF registers. // This ensures that each time the first frame is played back, the state of the // GPU is the same for each playback loop. m_CurrentFrame = m_FrameRangeStart; LoadRegisters(); LoadTextureMemory(); FlushWGP(); } if (m_FrameWrittenCb) m_FrameWrittenCb(); if (m_EarlyMemoryUpdates && m_CurrentFrame == m_FrameRangeStart) WriteAllMemoryUpdates(); WriteFrame(m_File->GetFrame(m_CurrentFrame), m_FrameInfo[m_CurrentFrame]); ++m_CurrentFrame; return CPU::State::Running; }
void FifoPlayer::WriteFrame(const FifoFrameInfo &frame, const AnalyzedFrameInfo &info) { // Core timing information m_CyclesPerFrame = SystemTimers::GetTicksPerSecond() / 60; m_ElapsedCycles = 0; m_FrameFifoSize = frame.fifoDataSize; // Determine start and end objects u32 numObjects = (u32)(info.objectStarts.size()); u32 drawStart = std::min(numObjects, m_ObjectRangeStart); u32 drawEnd = std::min(numObjects - 1, m_ObjectRangeEnd); u32 position = 0; u32 memoryUpdate = 0; // Skip memory updates during frame if true if (m_EarlyMemoryUpdates) { memoryUpdate = (u32)(frame.memoryUpdates.size()); } if (numObjects > 0) { u32 objectNum = 0; // Write fifo data skipping objects before the draw range while (objectNum < drawStart) { WriteFramePart(position, info.objectStarts[objectNum], memoryUpdate, frame, info); position = info.objectEnds[objectNum]; ++objectNum; } // Write objects in draw range if (objectNum < numObjects && drawStart <= drawEnd) { objectNum = drawEnd; WriteFramePart(position, info.objectEnds[objectNum], memoryUpdate, frame, info); position = info.objectEnds[objectNum]; ++objectNum; } // Write fifo data skipping objects after the draw range while (objectNum < numObjects) { WriteFramePart(position, info.objectStarts[objectNum], memoryUpdate, frame, info); position = info.objectEnds[objectNum]; ++objectNum; } } // Write data after the last object WriteFramePart(position, frame.fifoDataSize, memoryUpdate, frame, info); FlushWGP(); }
void FifoPlayer::LoadMemory() { UReg_MSR newMSR; newMSR.DR = 1; newMSR.IR = 1; MSR = newMSR.Hex; PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff; PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002; PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff; PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002; PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff; PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a; Memory::Clear(); SetupFifo(); u32 *regs = m_File->GetBPMem(); for (int i = 0; i < FifoDataFile::BP_MEM_SIZE; ++i) { if (ShouldLoadBP(i)) LoadBPReg(i, regs[i]); } regs = m_File->GetCPMem(); LoadCPReg(0x30, regs[0x30]); LoadCPReg(0x40, regs[0x40]); LoadCPReg(0x50, regs[0x50]); LoadCPReg(0x60, regs[0x60]); for (int i = 0; i < 8; ++i) { LoadCPReg(0x70 + i, regs[0x70 + i]); LoadCPReg(0x80 + i, regs[0x80 + i]); LoadCPReg(0x90 + i, regs[0x90 + i]); } for (int i = 0; i < 16; ++i) { LoadCPReg(0xa0 + i, regs[0xa0 + i]); LoadCPReg(0xb0 + i, regs[0xb0 + i]); } regs = m_File->GetXFMem(); for (int i = 0; i < FifoDataFile::XF_MEM_SIZE; i += 16) LoadXFMem16(i, ®s[i]); regs = m_File->GetXFRegs(); for (int i = 0; i < FifoDataFile::XF_REGS_SIZE; ++i) LoadXFReg(i, regs[i]); FlushWGP(); }
void FifoPlayer::LoadMemory() { Memory::Clear(); SetupFifo(); u32 *regs = m_File->GetBPMem(); for (int i = 0; i < FifoDataFile::BP_MEM_SIZE; ++i) { if (ShouldLoadBP(i)) LoadBPReg(i, regs[i]); } regs = m_File->GetCPMem(); LoadCPReg(0x30, regs[0x30]); LoadCPReg(0x40, regs[0x40]); LoadCPReg(0x50, regs[0x50]); LoadCPReg(0x60, regs[0x60]); for (int i = 0; i < 8; ++i) { LoadCPReg(0x70 + i, regs[0x70 + i]); LoadCPReg(0x80 + i, regs[0x80 + i]); LoadCPReg(0x90 + i, regs[0x90 + i]); } for (int i = 0; i < 16; ++i) { LoadCPReg(0xa0 + i, regs[0xa0 + i]); LoadCPReg(0xb0 + i, regs[0xb0 + i]); } regs = m_File->GetXFMem(); for (int i = 0; i < FifoDataFile::XF_MEM_SIZE; i += 16) LoadXFMem16(i, ®s[i]); regs = m_File->GetXFRegs(); for (int i = 0; i < FifoDataFile::XF_REGS_SIZE; ++i) LoadXFReg(i, regs[i]); FlushWGP(); }
void FifoPlayer::LoadMemory() { UReg_MSR newMSR; newMSR.DR = 1; newMSR.IR = 1; MSR = newMSR.Hex; PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff; PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002; PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff; PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002; PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff; PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a; PowerPC::DBATUpdated(); PowerPC::IBATUpdated(); SetupFifo(); LoadRegisters(); LoadTextureMemory(); FlushWGP(); }
void FifoPlayer::SetupFifo() { WriteCP(0x02, 0); // disable read, BP, interrupts WriteCP(0x04, 7); // clear overflow, underflow, metrics const FifoFrameInfo& frame = m_File->GetFrame(m_CurrentFrame); // Set fifo bounds WriteCP(0x20, frame.fifoStart); WriteCP(0x22, frame.fifoStart >> 16); WriteCP(0x24, frame.fifoEnd); WriteCP(0x26, frame.fifoEnd >> 16); // Set watermarks u32 fifoSize = frame.fifoEnd - frame.fifoStart; WriteCP(0x28, fifoSize); WriteCP(0x2a, fifoSize >> 16); WriteCP(0x2c, 0); WriteCP(0x2e, 0); // Set R/W pointers to fifo start WriteCP(0x30, 0); WriteCP(0x32, 0); WriteCP(0x34, frame.fifoStart); WriteCP(0x36, frame.fifoStart >> 16); WriteCP(0x38, frame.fifoStart); WriteCP(0x3a, frame.fifoStart >> 16); // Set fifo bounds WritePI(12, frame.fifoStart); WritePI(16, frame.fifoEnd); // Set write pointer WritePI(20, frame.fifoStart); FlushWGP(); WritePI(20, frame.fifoStart); WriteCP(0x02, 17); // enable read & GP link }
void FifoPlayer::SetupFifo() { WriteCP(CommandProcessor::CTRL_REGISTER, 0); // disable read, BP, interrupts WriteCP(CommandProcessor::CLEAR_REGISTER, 7); // clear overflow, underflow, metrics const FifoFrameInfo& frame = m_File->GetFrame(m_CurrentFrame); // Set fifo bounds WriteCP(CommandProcessor::FIFO_BASE_LO, frame.fifoStart); WriteCP(CommandProcessor::FIFO_BASE_HI, frame.fifoStart >> 16); WriteCP(CommandProcessor::FIFO_END_LO, frame.fifoEnd); WriteCP(CommandProcessor::FIFO_END_HI, frame.fifoEnd >> 16); // Set watermarks, high at 75%, low at 0% u32 hi_watermark = (frame.fifoEnd - frame.fifoStart) * 3 / 4; WriteCP(CommandProcessor::FIFO_HI_WATERMARK_LO, hi_watermark); WriteCP(CommandProcessor::FIFO_HI_WATERMARK_HI, hi_watermark >> 16); WriteCP(CommandProcessor::FIFO_LO_WATERMARK_LO, 0); WriteCP(CommandProcessor::FIFO_LO_WATERMARK_HI, 0); // Set R/W pointers to fifo start WriteCP(CommandProcessor::FIFO_RW_DISTANCE_LO, 0); WriteCP(CommandProcessor::FIFO_RW_DISTANCE_HI, 0); WriteCP(CommandProcessor::FIFO_WRITE_POINTER_LO, frame.fifoStart); WriteCP(CommandProcessor::FIFO_WRITE_POINTER_HI, frame.fifoStart >> 16); WriteCP(CommandProcessor::FIFO_READ_POINTER_LO, frame.fifoStart); WriteCP(CommandProcessor::FIFO_READ_POINTER_HI, frame.fifoStart >> 16); // Set fifo bounds WritePI(ProcessorInterface::PI_FIFO_BASE, frame.fifoStart); WritePI(ProcessorInterface::PI_FIFO_END, frame.fifoEnd); // Set write pointer WritePI(ProcessorInterface::PI_FIFO_WPTR, frame.fifoStart); FlushWGP(); WritePI(ProcessorInterface::PI_FIFO_WPTR, frame.fifoStart); WriteCP(CommandProcessor::CTRL_REGISTER, 17); // enable read & GP link }