Beispiel #1
0
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;
}
Beispiel #2
0
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
	}
}
Beispiel #3
0
void CVIF::ExecuteVu1(bool singleStep)
{
	if(!IsVu1Running()) return;
#ifdef PROFILE
	CProfilerZone profilerZone(PROFILE_VIFZONE);
#endif	
	m_pVPU[1]->Execute(singleStep);
}
Beispiel #4
0
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());
	}
}
Beispiel #5
0
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;
	}
}
Beispiel #6
0
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;
	}
}
Beispiel #7
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
	}
}
Beispiel #8
0
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();
}
Beispiel #9
0
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;
}
Beispiel #10
0
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;
}