uint32 CVIF::ProcessDMAPacket(unsigned int vpuNumber, uint32 address, uint32 qwc, bool tagIncluded) { #ifdef _DEBUG CLog::GetInstance().Print(LOG_NAME, "vif%i : Processing packet @ 0x%0.8X, qwc = 0x%X, tagIncluded = %i\r\n", vpuNumber, address, qwc, static_cast<int>(tagIncluded)); #endif #ifdef PROFILE CProfilerZone profilerZone(PROFILE_VIFZONE); #endif m_stream[vpuNumber]->SetDmaParams(address, qwc * 0x10); if(tagIncluded) { m_stream[vpuNumber]->Read(NULL, 8); } m_pVPU[vpuNumber]->ProcessPacket(*m_stream[vpuNumber]); uint32 remainingSize = m_stream[vpuNumber]->GetRemainingDmaTransferSize(); assert((remainingSize & 0x0F) == 0); remainingSize /= 0x10; return qwc - remainingSize; }
void CPS2VM::UpdateEe() { #ifdef PROFILE CProfilerZone profilerZone(m_eeProfilerZone); #endif while(m_eeExecutionTicks > 0) { int executed = m_ee->ExecuteCpu(m_singleStepEe ? 1 : m_eeExecutionTicks); if(m_ee->IsCpuIdle()) { executed = m_eeExecutionTicks; } m_eeExecutionTicks -= executed; m_ee->CountTicks(executed); m_vblankTicks -= executed; //Stop executing if executing VU subroutine if(m_ee->m_EE.m_State.callMsEnabled) break; #ifdef DEBUGGER_INCLUDED if(m_singleStepEe) break; if(m_ee->m_executor.MustBreak()) break; #endif } }
void CVIF::ExecuteVu1(bool singleStep) { if(!IsVu1Running()) return; #ifdef PROFILE CProfilerZone profilerZone(PROFILE_VIFZONE); #endif m_pVPU[1]->Execute(singleStep); }
void CVPU::Execute(bool singleStep) { #ifdef PROFILE CProfilerZone profilerZone(m_vuProfilerZone); #endif unsigned int quota = singleStep ? 1 : 5000; assert(IsRunning()); m_executor.Execute(quota); if(m_ctx->m_State.nHasException) { //E bit encountered m_vif.SetStat(m_vif.GetStat() & ~GetVbs()); } }
void CVpu::Execute(bool singleStep) { if(!m_running) return; #ifdef PROFILE CProfilerZone profilerZone(m_vuProfilerZone); #endif unsigned int quota = singleStep ? 1 : 5000; m_executor.Execute(quota); if(m_ctx->m_State.nHasException) { //E bit encountered m_running = false; } }
void CPS2VM::UpdateSpu() { #ifdef PROFILE CProfilerZone profilerZone(m_spuProfilerZone); #endif unsigned int blockOffset = (BLOCK_SIZE * m_currentSpuBlock); int16* samplesSpu0 = m_samples + blockOffset; m_iop->m_spuCore0.Render(samplesSpu0, BLOCK_SIZE, 44100); if(m_iop->m_spuCore1.IsEnabled()) { int16 samplesSpu1[BLOCK_SIZE]; m_iop->m_spuCore1.Render(samplesSpu1, BLOCK_SIZE, 44100); for(unsigned int i = 0; i < BLOCK_SIZE; i++) { int32 resultSample = static_cast<int32>(samplesSpu0[i]) + static_cast<int32>(samplesSpu1[i]); resultSample = std::max<int32>(resultSample, SHRT_MIN); resultSample = std::min<int32>(resultSample, SHRT_MAX); samplesSpu0[i] = static_cast<int16>(resultSample); } } m_currentSpuBlock++; if(m_currentSpuBlock == BLOCK_COUNT) { if(m_soundHandler) { if(m_soundHandler->HasFreeBuffers()) { m_soundHandler->RecycleBuffers(); } m_soundHandler->Write(m_samples, BLOCK_SIZE * BLOCK_COUNT, 44100); } m_currentSpuBlock = 0; } }
void CPS2VM::UpdateIop() { #ifdef PROFILE CProfilerZone profilerZone(m_iopProfilerZone); #endif while(m_iopExecutionTicks > 0) { int executed = m_iop->ExecuteCpu(m_singleStepIop ? 1 : m_iopExecutionTicks); if(m_iop->IsCpuIdle()) { executed = m_iopExecutionTicks; } m_iopExecutionTicks -= executed; m_spuUpdateTicks -= executed; m_iop->CountTicks(executed); #ifdef DEBUGGER_INCLUDED if(m_singleStepIop) break; if(m_iop->m_executor.MustBreak()) break; #endif } }
void CPS2VM::EmuThread() { fesetround(FE_TOWARDZERO); CProfiler::GetInstance().SetWorkThread(); #ifdef PROFILE CProfilerZone profilerZone(m_otherProfilerZone); #endif m_ee->m_executor.AddExceptionHandler(); while(1) { while(m_mailBox.IsPending()) { m_mailBox.ReceiveCall(); } if(m_nEnd) break; if(m_nStatus == PAUSED) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } if(m_nStatus == RUNNING) { if(m_spuUpdateTicks <= 0) { UpdateSpu(); m_spuUpdateTicks += SPU_UPDATE_TICKS; } //EE execution { //Check vblank stuff if(m_vblankTicks <= 0) { m_inVblank = !m_inVblank; if(m_inVblank) { m_vblankTicks += VBLANK_TICKS; m_ee->NotifyVBlankStart(); m_iop->NotifyVBlankStart(); if(m_ee->m_gs != NULL) { #ifdef PROFILE CProfilerZone profilerZone(m_gsSyncProfilerZone); #endif m_ee->m_gs->SetVBlank(); } if(m_pad != NULL) { m_pad->Update(m_ee->m_ram); } #ifdef PROFILE { CProfiler::GetInstance().CountCurrentZone(); auto stats = CProfiler::GetInstance().GetStats(); ProfileFrameDone(stats); CProfiler::GetInstance().Reset(); } #endif } else { m_vblankTicks += ONSCREEN_TICKS; m_ee->NotifyVBlankEnd(); m_iop->NotifyVBlankEnd(); if(m_ee->m_gs != NULL) { m_ee->m_gs->ResetVBlank(); } } } //EE CPU is 8 times faster than the IOP CPU static const int tickStep = 480; m_eeExecutionTicks += tickStep; m_iopExecutionTicks += tickStep / 8; UpdateEe(); UpdateIop(); m_ee->m_vpu0->Execute(m_singleStepVu0); m_ee->m_vpu1->Execute(m_singleStepVu1); } #ifdef DEBUGGER_INCLUDED if( m_ee->m_executor.MustBreak() || m_iop->m_executor.MustBreak() || m_ee->m_vpu1->MustBreak() || m_singleStepEe || m_singleStepIop || m_singleStepVu0 || m_singleStepVu1) { m_nStatus = PAUSED; m_singleStepEe = false; m_singleStepIop = false; m_singleStepVu0 = false; m_singleStepVu1 = false; OnRunningStateChange(); OnMachineStateChange(); } #endif } } m_ee->m_executor.RemoveExceptionHandler(); }
uint32 CGIF::ProcessPacket(uint8* memory, uint32 address, uint32 end, const CGsPacketMetadata& packetMetadata) { std::unique_lock<std::mutex> pathLock(m_pathMutex); static CGSHandler::RegisterWriteList writeList; #ifdef PROFILE CProfilerZone profilerZone(m_gifProfilerZone); #endif #ifdef _DEBUG CLog::GetInstance().Print(LOG_NAME, "Received GIF packet on path %d at 0x%0.8X of 0x%0.8X bytes.\r\n", packetMetadata.pathIndex, address, end - address); #endif writeList.clear(); uint32 start = address; while(address < end) { if(m_loops == 0) { if(m_eop) { m_eop = false; break; } //We need to update the registers TAG tag = *reinterpret_cast<TAG*>(&memory[address]); address += 0x10; m_loops = tag.loops; m_cmd = tag.cmd; m_regs = tag.nreg; m_regList = tag.regs; m_eop = (tag.eop != 0); if(m_cmd != 1) { if(tag.pre != 0) { writeList.push_back(CGSHandler::RegisterWrite(GS_REG_PRIM, static_cast<uint64>(tag.prim))); } } if(m_regs == 0) m_regs = 0x10; m_regsTemp = m_regs; continue; } switch(m_cmd) { case 0x00: address += ProcessPacked(writeList, memory, address, end); break; case 0x01: address += ProcessRegList(writeList, memory, address, end); break; case 0x02: case 0x03: address += ProcessImage(memory, address, end); break; } } if(m_loops == 0) { if(m_eop) { m_eop = false; } } if((m_gs != nullptr) && !writeList.empty()) { m_gs->WriteRegisterMassively(writeList.data(), static_cast<unsigned int>(writeList.size()), &packetMetadata); } #ifdef _DEBUG CLog::GetInstance().Print(LOG_NAME, "Processed 0x%0.8X bytes.\r\n", address - start); #endif return address - start; }
uint32 CGIF::ProcessPacket(uint8* memory, uint32 address, uint32 end, const CGsPacketMetadata& packetMetadata) { std::unique_lock<std::mutex> pathLock(m_pathMutex); static CGSHandler::RegisterWriteList writeList; static const auto flushWriteList = [] (CGSHandler* gs, const CGsPacketMetadata& packetMetadata) { if((gs != nullptr) && !writeList.empty()) { gs->WriteRegisterMassively(writeList.data(), static_cast<unsigned int>(writeList.size()), &packetMetadata); } writeList.clear(); }; #ifdef PROFILE CProfilerZone profilerZone(m_gifProfilerZone); #endif #if defined(_DEBUG) && defined(DEBUGGER_INCLUDED) CLog::GetInstance().Print(LOG_NAME, "Received GIF packet on path %d at 0x%0.8X of 0x%0.8X bytes.\r\n", packetMetadata.pathIndex, address, end - address); #endif writeList.clear(); uint32 start = address; while(address < end) { if(m_loops == 0) { if(m_eop) { m_eop = false; break; } //We need to update the registers TAG tag = *reinterpret_cast<TAG*>(&memory[address]); address += 0x10; m_loops = tag.loops; m_cmd = tag.cmd; m_regs = tag.nreg; m_regList = tag.regs; m_eop = (tag.eop != 0); if(m_cmd != 1) { if(tag.pre != 0) { writeList.push_back(CGSHandler::RegisterWrite(GS_REG_PRIM, static_cast<uint64>(tag.prim))); } } if(m_regs == 0) m_regs = 0x10; m_regsTemp = m_regs; continue; } switch(m_cmd) { case 0x00: address += ProcessPacked(writeList, memory, address, end); break; case 0x01: address += ProcessRegList(writeList, memory, address, end); break; case 0x02: case 0x03: //We need to flush our list here because image data can be embedded in a GIF packet //that specifies pixel transfer information in GS registers (and that has to be send first) //This is done by FFX flushWriteList(m_gs, packetMetadata); address += ProcessImage(memory, address, end); break; } } if(m_loops == 0) { if(m_eop) { m_eop = false; } } flushWriteList(m_gs, packetMetadata); #ifdef _DEBUG CLog::GetInstance().Print(LOG_NAME, "Processed 0x%0.8X bytes.\r\n", address - start); #endif return address - start; }