Beispiel #1
0
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, &regs[i]);

	regs = m_File->GetXFRegs();
	for (int i = 0; i < FifoDataFile::XF_REGS_SIZE; ++i)
		LoadXFReg(i, regs[i]);

	FlushWGP();
}
Beispiel #2
0
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, &regs[i]);

	regs = m_File->GetXFRegs();
	for (int i = 0; i < FifoDataFile::XF_REGS_SIZE; ++i)
		LoadXFReg(i, regs[i]);

	FlushWGP();
}
Beispiel #3
0
void FifoPlayer::LoadRegisters()
{
  const 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, &regs[i]);

  regs = m_File->GetXFRegs();
  for (int i = 0; i < FifoDataFile::XF_REGS_SIZE; ++i)
    LoadXFReg(i, regs[i]);
}
inline u32 Decode(const u8* end)
{
	const u8 *opcodeStart = g_VideoData.GetReadPosition();
	if (opcodeStart == end)
		return 0;

	u8 cmd_byte = g_VideoData.Read<u8>();
	size_t distance = (size_t)(end - g_VideoData.GetReadPosition());
	u32 cycles;

	switch (cmd_byte)
	{
	case GX_NOP:
	{
		cycles = GX_NOP_CYCLES; // Hm, this means that we scan over nop streams pretty slowly...
	}
	break;
	case GX_UNKNOWN_RESET:
	{
		cycles = GX_NOP_CYCLES; // Datel software uses this command
		DEBUG_LOG(VIDEO, "GX Reset?: %08x", cmd_byte);		
	}
	break;
	case GX_LOAD_CP_REG:
	{
		if (sizeCheck && distance < GX_LOAD_CP_REG_SIZE)
			return 0;
		cycles = GX_LOAD_CP_REG_CYCLES;
		u8 sub_cmd = g_VideoData.Read<u8>();
		u32 value = g_VideoData.Read<u32>();
		LoadCPReg(sub_cmd, value);
		INCSTAT(stats.thisFrame.numCPLoads);
	}
	break;
	case GX_LOAD_XF_REG:
	{
		if (sizeCheck && distance < GX_LOAD_XF_REG_SIZE)
			return 0;
		u32 Cmd2 = g_VideoData.Read<u32>();
		distance -= GX_LOAD_XF_REG_SIZE;
		int transfer_size = ((Cmd2 >> 16) & 15) + 1;
		if (sizeCheck && (distance < (transfer_size * sizeof(u32))))
			return 0;
		cycles = GX_LOAD_XF_REG_BASE_CYCLES + GX_LOAD_XF_REG_TRANSFER_CYCLES * transfer_size;
		u32 xf_address = Cmd2 & 0xFFFF;
		LoadXFReg(transfer_size, xf_address);

		INCSTAT(stats.thisFrame.numXFLoads);
	}
	break;
	case GX_LOAD_INDX_A: //used for position matrices
	{	
		if (sizeCheck && distance < GX_LOAD_INDX_A_SIZE)
			return 0;
		cycles = GX_LOAD_INDX_A_CYCLES;
		LoadIndexedXF(g_VideoData.Read<u32>(), 0xC);
	}
	break;
	case GX_LOAD_INDX_B: //used for normal matrices
	{
		if (sizeCheck && distance < GX_LOAD_INDX_B_SIZE)
			return 0;
		cycles = GX_LOAD_INDX_B_CYCLES;
		LoadIndexedXF(g_VideoData.Read<u32>(), 0xD);
	}
	break;
	case GX_LOAD_INDX_C: //used for postmatrices
	{
		if (sizeCheck && distance < GX_LOAD_INDX_C_SIZE)
			return 0;
		cycles = GX_LOAD_INDX_C_CYCLES;
		LoadIndexedXF(g_VideoData.Read<u32>(), 0xE);
	}
	break;
	case GX_LOAD_INDX_D: //used for lights
	{
		if (sizeCheck && distance < GX_LOAD_INDX_D_SIZE)
			return 0;
		cycles = GX_LOAD_INDX_D_CYCLES;
		LoadIndexedXF(g_VideoData.Read<u32>(), 0xF);
	}
	break;
	case GX_CMD_CALL_DL:
	{
		if (sizeCheck && distance < GX_CMD_CALL_DL_SIZE)
			return 0;
		u32 address = g_VideoData.Read<u32>();
		u32 count = g_VideoData.Read<u32>();
		cycles = GX_CMD_CALL_DL_BASE_CYCLES + InterpretDisplayList(address, count);
	}
	break;
	case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that
	{	
		cycles = GX_CMD_UNKNOWN_METRICS_CYCLES;
		DEBUG_LOG(VIDEO, "GX 0x44: %08x", cmd_byte);
	}
	break;
	case GX_CMD_INVL_VC: // Invalidate Vertex Cache	
	{
		cycles = GX_CMD_INVL_VC_CYCLES;
		DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)");
	}
	break;
	case GX_LOAD_BP_REG:
	{
		if (sizeCheck && distance < GX_LOAD_BP_REG_SIZE)
			return 0;
		cycles = GX_LOAD_BP_REG_CYCLES;
		u32 bp_cmd = g_VideoData.Read<u32>();
		LoadBPReg(bp_cmd);
		INCSTAT(stats.thisFrame.numBPLoads);
	}
	break;
		// draw primitives 
	default:
		if ((cmd_byte & GX_DRAW_PRIMITIVES) == 0x80)
		{
			// load vertices
			if (sizeCheck && distance < GX_DRAW_PRIMITIVES_SIZE)
				return 0;
			
			u32 count = g_VideoData.Read<u16>();
			distance -= GX_DRAW_PRIMITIVES_SIZE;
			if (count)
			{
				VertexLoaderParameters parameters;
				parameters.count = count;				
				parameters.buf_size = distance;
				parameters.primitive = (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT;
				parameters.vtx_attr_group = cmd_byte & GX_VAT_MASK;
				parameters.needloaderrefresh = (g_main_cp_state.attr_dirty & (1 << parameters.vtx_attr_group)) != 0;
				parameters.skip_draw = g_bSkipCurrentFrame;
				parameters.VtxDesc = &g_main_cp_state.vtx_desc;
				parameters.VtxAttr = &g_main_cp_state.vtx_attr[parameters.vtx_attr_group];
				parameters.source = g_VideoData.GetReadPosition();
				g_main_cp_state.attr_dirty &= ~(1 << parameters.vtx_attr_group);
				u32 readsize = 0;
				u32 writesize = 0;
				if (VertexLoaderManager::ConvertVertices(parameters, readsize, writesize))
				{
					cycles = GX_NOP_CYCLES + GX_DRAW_PRIMITIVES_CYCLES * parameters.count;
					g_VideoData.ReadSkip(readsize);
					VertexManagerBase::s_pCurBufferPointer += writesize;
				}
				else
				{
					return 0;
				}
			}
			else
			{
				cycles = GX_NOP_CYCLES;
			}
		}
		else
		{
			if (!s_bFifoErrorSeen)
Beispiel #5
0
u8* OpcodeDecoder_Run(DataReader src, u32* cycles, bool in_display_list)
{
	u32 totalCycles = 0;
	u8* opcodeStart;
	while (true)
	{
		opcodeStart = src.GetPointer();

		if (!src.size())
			goto end;

		u8 cmd_byte = src.Read<u8>();
		int refarray;
		switch (cmd_byte)
		{
		case GX_NOP:
			totalCycles += 6; // Hm, this means that we scan over nop streams pretty slowly...
			break;

		case GX_UNKNOWN_RESET:
			totalCycles += 6; // Datel software uses this command
			DEBUG_LOG(VIDEO, "GX Reset?: %08x", cmd_byte);
			break;

		case GX_LOAD_CP_REG:
			{
				if (src.size() < 1 + 4)
					goto end;
				totalCycles += 12;
				u8 sub_cmd = src.Read<u8>();
				u32 value =  src.Read<u32>();
				LoadCPReg(sub_cmd, value, is_preprocess);
				if (!is_preprocess)
					INCSTAT(stats.thisFrame.numCPLoads);
			}
			break;

		case GX_LOAD_XF_REG:
			{
				if (src.size() < 4)
					goto end;
				u32 Cmd2 =  src.Read<u32>();
				int transfer_size = ((Cmd2 >> 16) & 15) + 1;
				if (src.size() < transfer_size * sizeof(u32))
					goto end;
				totalCycles += 18 + 6 * transfer_size;
				if (!is_preprocess)
				{
					u32 xf_address = Cmd2 & 0xFFFF;
					LoadXFReg(transfer_size, xf_address, src);

					INCSTAT(stats.thisFrame.numXFLoads);
				}
				src.Skip<u32>(transfer_size);
			}
			break;

		case GX_LOAD_INDX_A: //used for position matrices
			refarray = 0xC;
			goto load_indx;
		case GX_LOAD_INDX_B: //used for normal matrices
			refarray = 0xD;
			goto load_indx;
		case GX_LOAD_INDX_C: //used for postmatrices
			refarray = 0xE;
			goto load_indx;
		case GX_LOAD_INDX_D: //used for lights
			refarray = 0xF;
			goto load_indx;
		load_indx:
			if (src.size() < 4)
				goto end;
			totalCycles += 6;
			if (is_preprocess)
				PreprocessIndexedXF(src.Read<u32>(), refarray);
			else
				LoadIndexedXF(src.Read<u32>(), refarray);
			break;

		case GX_CMD_CALL_DL:
			{
				if (src.size() < 8)
					goto end;
				u32 address = src.Read<u32>();
				u32 count = src.Read<u32>();

				if (in_display_list)
				{
					totalCycles += 6;
					WARN_LOG(VIDEO,"recursive display list detected");
				}
				else
				{
					if (is_preprocess)
						InterpretDisplayListPreprocess(address, count);
					else
						totalCycles += 6 + InterpretDisplayList(address, count);
				}
			}
			break;

		case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that
			totalCycles += 6;
			DEBUG_LOG(VIDEO, "GX 0x44: %08x", cmd_byte);
			break;

		case GX_CMD_INVL_VC: // Invalidate Vertex Cache
			totalCycles += 6;
			DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)");
			break;

		case GX_LOAD_BP_REG:
			// In skipped_frame case: We have to let BP writes through because they set
			// tokens and stuff.  TODO: Call a much simplified LoadBPReg instead.
			{
				if (src.size() < 4)
					goto end;
				totalCycles += 12;
				u32 bp_cmd = src.Read<u32>();
				if (is_preprocess)
				{
					LoadBPRegPreprocess(bp_cmd);
				}
				else
				{
					LoadBPReg(bp_cmd);
					INCSTAT(stats.thisFrame.numBPLoads);
				}
			}
			break;

		// draw primitives
		default:
			if ((cmd_byte & 0xC0) == 0x80)
			{
				// load vertices
				if (src.size() < 2)
					goto end;
				u16 num_vertices = src.Read<u16>();
				int bytes = VertexLoaderManager::RunVertices(
					cmd_byte & GX_VAT_MASK,   // Vertex loader index (0 - 7)
					(cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT,
					num_vertices,
					src,
					Fifo::g_bSkipCurrentFrame,
					is_preprocess);

				if (bytes < 0)
					goto end;

				src.Skip(bytes);

				// 4 GPU ticks per vertex, 3 CPU ticks per GPU tick
				totalCycles += num_vertices * 4 * 3 + 6;
			}
			else
			{
				if (!s_bFifoErrorSeen)
					UnknownOpcode(cmd_byte, opcodeStart, is_preprocess);
				ERROR_LOG(VIDEO, "FIFO: Unknown Opcode(0x%02x @ %p, preprocessing = %s)", cmd_byte, opcodeStart, is_preprocess ? "yes" : "no");
				s_bFifoErrorSeen = true;
				totalCycles += 1;
			}
			break;
		}

		// Display lists get added directly into the FIFO stream
		if (!is_preprocess && g_bRecordFifoData && cmd_byte != GX_CMD_CALL_DL)
		{
			u8* opcodeEnd;
			opcodeEnd = src.GetPointer();
			FifoRecorder::GetInstance().WriteGPCommand(opcodeStart, u32(opcodeEnd - opcodeStart));
		}
	}
Beispiel #6
0
u8* OpcodeDecoder_Run(DataReader& reader, u32* cycles)
{
	u32 totalCycles = 0;
	u8* opcodeStart;
	while (true)
	{
		opcodeStart = reader.GetReadPosition();
		if (!reader.size())
			goto end;

		u8 cmd_byte = reader.Read<u8>();
		size_t distance = reader.size();

		switch (cmd_byte)
		{
		case GX_NOP:
		{
			totalCycles += GX_NOP_CYCLES; // Hm, this means that we scan over nop streams pretty slowly...
		}
		break;
		case GX_UNKNOWN_RESET:
		{
			totalCycles += GX_NOP_CYCLES; // Datel software uses this command
			DEBUG_LOG(VIDEO, "GX Reset?: %08x", cmd_byte);
		}
		break;
		case GX_LOAD_CP_REG:
		{
			if (sizeCheck && distance < GX_LOAD_CP_REG_SIZE)
				goto end;
			totalCycles += GX_LOAD_CP_REG_CYCLES;
			u8 sub_cmd = reader.Read<u8>();
			u32 value = reader.Read<u32>();
			LoadCPReg<is_preprocess>(sub_cmd, value);
			if (!is_preprocess)
				INCSTAT(stats.thisFrame.numCPLoads);
		}
		break;
		case GX_LOAD_XF_REG:
		{
			if (sizeCheck && distance < GX_LOAD_XF_REG_SIZE)
				goto end;
			u32 Cmd2 = reader.Read<u32>();
			distance -= GX_LOAD_XF_REG_SIZE;
			int transfer_size = ((Cmd2 >> 16) & 15) + 1;
			if (sizeCheck && distance < (transfer_size * sizeof(u32)))
				goto end;
			totalCycles += GX_LOAD_XF_REG_BASE_CYCLES + GX_LOAD_XF_REG_TRANSFER_CYCLES * transfer_size;
			if (is_preprocess)
			{
				reader.ReadSkip(transfer_size * sizeof(u32));
			}
			else
			{
				u32 xf_address = Cmd2 & 0xFFFF;
				LoadXFReg(transfer_size, xf_address);
				INCSTAT(stats.thisFrame.numXFLoads);
			}
		}
		break;
		case GX_LOAD_INDX_A: //used for position matrices
		case GX_LOAD_INDX_B: //used for normal matrices
		case GX_LOAD_INDX_C: //used for postmatrices
		case GX_LOAD_INDX_D: //used for lights
		{
			if (sizeCheck && distance < GX_LOAD_INDX_SIZE)
				goto end;
			totalCycles += GX_LOAD_INDX_CYCLES;
			const s32 ref_array = (cmd_byte >> 3) + 8;
			if (is_preprocess)
				PreprocessIndexedXF(reader.Read<u32>(), ref_array);
			else
				LoadIndexedXF(reader.Read<u32>(), ref_array);
		}
		break;
		case GX_CMD_CALL_DL:
		{
			if (sizeCheck && distance < GX_CMD_CALL_DL_SIZE)
				goto end;
			u32 address = reader.Read<u32>();
			u32 count = reader.Read<u32>();
			if (is_preprocess)
				InterpretDisplayListPreprocess(address, count);
			else
				totalCycles += GX_CMD_CALL_DL_BASE_CYCLES + InterpretDisplayList(address, count);
		}
		break;
		case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that
		{
			totalCycles += GX_CMD_UNKNOWN_METRICS_CYCLES;
			DEBUG_LOG(VIDEO, "GX 0x44: %08x", cmd_byte);
		}
		break;
		case GX_CMD_INVL_VC: // Invalidate Vertex Cache	
		{
			totalCycles += GX_CMD_INVL_VC_CYCLES;
			DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)");
		}
		break;
		case GX_LOAD_BP_REG:
		{
			if (sizeCheck && distance < GX_LOAD_BP_REG_SIZE)
				goto end;
			totalCycles += GX_LOAD_BP_REG_CYCLES;
			u32 bp_cmd = reader.Read<u32>();
			if (is_preprocess)
			{
				LoadBPRegPreprocess(bp_cmd);
			}
			else
			{
				LoadBPReg(bp_cmd);
				INCSTAT(stats.thisFrame.numBPLoads);
			}
		}
		break;
		// draw primitives 
		default:
			if ((cmd_byte & GX_DRAW_PRIMITIVES) == 0x80)
			{
				// load vertices
				if (sizeCheck && distance < GX_DRAW_PRIMITIVES_SIZE)
					goto end;

				u32 count = reader.Read<u16>();
				distance -= GX_DRAW_PRIMITIVES_SIZE;
				if (count)
				{
					CPState& state = is_preprocess ? g_preprocess_cp_state : g_main_cp_state;
					VertexLoaderParameters parameters;
					parameters.count = count;
					parameters.buf_size = distance;
					parameters.primitive = (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT;
					u32 vtx_attr_group = cmd_byte & GX_VAT_MASK;
					parameters.vtx_attr_group = vtx_attr_group;
					parameters.needloaderrefresh = (state.attr_dirty & (1u << vtx_attr_group)) != 0;
					parameters.skip_draw = g_bSkipCurrentFrame;
					parameters.VtxDesc = &state.vtx_desc;
					parameters.VtxAttr = &state.vtx_attr[vtx_attr_group];
					parameters.source = reader.GetReadPosition();
					state.attr_dirty &= ~(1 << vtx_attr_group);
					u32 readsize = 0;					
					if (is_preprocess)
					{
						u32 components = 0;
						VertexLoaderManager::GetVertexSizeAndComponents(parameters, readsize, components);
						readsize *= count;
						if (distance >= readsize)
						{
							totalCycles += GX_NOP_CYCLES + GX_DRAW_PRIMITIVES_CYCLES * parameters.count;
							reader.ReadSkip(readsize);
						}
						else
						{
							goto end;
						}
					}
					else
					{
						u32 writesize = 0;
						if (VertexLoaderManager::ConvertVertices(parameters, readsize, writesize))
						{
							totalCycles += GX_NOP_CYCLES + GX_DRAW_PRIMITIVES_CYCLES * parameters.count;
							reader.ReadSkip(readsize);
							VertexManagerBase::s_pCurBufferPointer += writesize;
						}
						else
						{
							goto end;
						}
					}
				}
				else
				{
					totalCycles += GX_NOP_CYCLES;
				}
			}
			else
			{
				if (!s_bFifoErrorSeen)
					UnknownOpcode(cmd_byte, opcodeStart, is_preprocess);
				ERROR_LOG(VIDEO, "FIFO: Unknown Opcode(0x%02x @ %p, preprocessing = %s)", cmd_byte, opcodeStart, is_preprocess ? "yes" : "no");
				s_bFifoErrorSeen = true;
				totalCycles += 1;
			}
			break;
		}