コード例 #1
0
ファイル: OpcodeDecoding.cpp プロジェクト: absolome/dolphin
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));
		}
	}
コード例 #2
0
ファイル: OpcodeDecoding.cpp プロジェクト: gamax92/Ishiiruka
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;
		}