1 #include <stdio.h>
2 #include <algorithm>
3 #include "../uint128.h"
4 #include "../Ps2Const.h"
5 #include "../Log.h"
6 #include "../FrameDump.h"
7 #include "../states/RegisterStateFile.h"
8 #include "GIF.h"
9 
10 #define QTEMP_INIT (0x3F800000)
11 
12 #define LOG_NAME ("ee_gif")
13 
14 #define STATE_REGS_XML ("gif/regs.xml")
15 #define STATE_REGS_M3P ("M3P")
16 #define STATE_REGS_ACTIVEPATH ("ActivePath")
17 #define STATE_REGS_LOOPS ("LOOPS")
18 #define STATE_REGS_CMD ("CMD")
19 #define STATE_REGS_REGS ("REGS")
20 #define STATE_REGS_REGSTEMP ("REGSTEMP")
21 #define STATE_REGS_REGLIST ("REGLIST")
22 #define STATE_REGS_EOP ("EOP")
23 #define STATE_REGS_QTEMP ("QTEMP")
24 
CGIF(CGSHandler * & gs,uint8 * ram,uint8 * spr)25 CGIF::CGIF(CGSHandler*& gs, uint8* ram, uint8* spr)
26     : m_qtemp(QTEMP_INIT)
27     , m_ram(ram)
28     , m_spr(spr)
29     , m_gs(gs)
30     , m_gifProfilerZone(CProfiler::GetInstance().RegisterZone("GIF"))
31 {
32 }
33 
Reset()34 void CGIF::Reset()
35 {
36 	m_path3Masked = false;
37 	m_activePath = 0;
38 	m_loops = 0;
39 	m_cmd = 0;
40 	m_regs = 0;
41 	m_regsTemp = 0;
42 	m_regList = 0;
43 	m_eop = false;
44 	m_qtemp = QTEMP_INIT;
45 	m_signalState = SIGNAL_STATE_NONE;
46 }
47 
LoadState(Framework::CZipArchiveReader & archive)48 void CGIF::LoadState(Framework::CZipArchiveReader& archive)
49 {
50 	CRegisterStateFile registerFile(*archive.BeginReadFile(STATE_REGS_XML));
51 	m_path3Masked = registerFile.GetRegister32(STATE_REGS_M3P) != 0;
52 	m_activePath = registerFile.GetRegister32(STATE_REGS_ACTIVEPATH);
53 	m_loops = static_cast<uint16>(registerFile.GetRegister32(STATE_REGS_LOOPS));
54 	m_cmd = static_cast<uint8>(registerFile.GetRegister32(STATE_REGS_CMD));
55 	m_regs = static_cast<uint8>(registerFile.GetRegister32(STATE_REGS_REGS));
56 	m_regsTemp = static_cast<uint8>(registerFile.GetRegister32(STATE_REGS_REGSTEMP));
57 	m_regList = registerFile.GetRegister64(STATE_REGS_REGLIST);
58 	m_eop = registerFile.GetRegister32(STATE_REGS_EOP) != 0;
59 	m_qtemp = registerFile.GetRegister32(STATE_REGS_QTEMP);
60 }
61 
SaveState(Framework::CZipArchiveWriter & archive)62 void CGIF::SaveState(Framework::CZipArchiveWriter& archive)
63 {
64 	CRegisterStateFile* registerFile = new CRegisterStateFile(STATE_REGS_XML);
65 	registerFile->SetRegister32(STATE_REGS_M3P, m_path3Masked ? 1 : 0);
66 	registerFile->SetRegister32(STATE_REGS_ACTIVEPATH, m_activePath);
67 	registerFile->SetRegister32(STATE_REGS_LOOPS, m_loops);
68 	registerFile->SetRegister32(STATE_REGS_CMD, m_cmd);
69 	registerFile->SetRegister32(STATE_REGS_REGS, m_regs);
70 	registerFile->SetRegister32(STATE_REGS_REGSTEMP, m_regsTemp);
71 	registerFile->SetRegister64(STATE_REGS_REGLIST, m_regList);
72 	registerFile->SetRegister32(STATE_REGS_EOP, m_eop ? 1 : 0);
73 	registerFile->SetRegister32(STATE_REGS_QTEMP, m_qtemp);
74 	archive.InsertFile(registerFile);
75 }
76 
ProcessPacked(const uint8 * memory,uint32 address,uint32 end)77 uint32 CGIF::ProcessPacked(const uint8* memory, uint32 address, uint32 end)
78 {
79 	uint32 start = address;
80 
81 	while((m_loops != 0) && (address < end))
82 	{
83 		while((m_regsTemp != 0) && (address < end))
84 		{
85 			uint64 temp = 0;
86 			uint32 regDesc = (uint32)((m_regList >> ((m_regs - m_regsTemp) * 4)) & 0x0F);
87 
88 			uint128 packet = *reinterpret_cast<const uint128*>(memory + address);
89 
90 			switch(regDesc)
91 			{
92 			case 0x00:
93 				//PRIM
94 				m_gs->WriteRegister(CGSHandler::RegisterWrite(GS_REG_PRIM, packet.nV0));
95 				break;
96 			case 0x01:
97 				//RGBA
98 				temp = (packet.nV[0] & 0xFF);
99 				temp |= (packet.nV[1] & 0xFF) << 8;
100 				temp |= (packet.nV[2] & 0xFF) << 16;
101 				temp |= (packet.nV[3] & 0xFF) << 24;
102 				temp |= ((uint64)m_qtemp << 32);
103 				m_gs->WriteRegister(CGSHandler::RegisterWrite(GS_REG_RGBAQ, temp));
104 				break;
105 			case 0x02:
106 				//ST
107 				m_qtemp = packet.nV2;
108 				m_gs->WriteRegister(CGSHandler::RegisterWrite(GS_REG_ST, packet.nD0));
109 				break;
110 			case 0x03:
111 				//UV
112 				temp = (packet.nV[0] & 0x7FFF);
113 				temp |= (packet.nV[1] & 0x7FFF) << 16;
114 				m_gs->WriteRegister(CGSHandler::RegisterWrite(GS_REG_UV, temp));
115 				break;
116 			case 0x04:
117 				//XYZF2
118 				temp = (packet.nV[0] & 0xFFFF);
119 				temp |= (packet.nV[1] & 0xFFFF) << 16;
120 				temp |= (uint64)(packet.nV[2] & 0x0FFFFFF0) << 28;
121 				temp |= (uint64)(packet.nV[3] & 0x00000FF0) << 52;
122 				if(packet.nV[3] & 0x8000)
123 				{
124 					m_gs->WriteRegister(CGSHandler::RegisterWrite(GS_REG_XYZF3, temp));
125 				}
126 				else
127 				{
128 					m_gs->WriteRegister(CGSHandler::RegisterWrite(GS_REG_XYZF2, temp));
129 				}
130 				break;
131 			case 0x05:
132 				//XYZ2
133 				temp = (packet.nV[0] & 0xFFFF);
134 				temp |= (packet.nV[1] & 0xFFFF) << 16;
135 				temp |= (uint64)(packet.nV[2] & 0xFFFFFFFF) << 32;
136 				if(packet.nV[3] & 0x8000)
137 				{
138 					m_gs->WriteRegister(CGSHandler::RegisterWrite(GS_REG_XYZ3, temp));
139 				}
140 				else
141 				{
142 					m_gs->WriteRegister(CGSHandler::RegisterWrite(GS_REG_XYZ2, temp));
143 				}
144 				break;
145 			case 0x06:
146 				//TEX0_1
147 				m_gs->WriteRegister(CGSHandler::RegisterWrite(GS_REG_TEX0_1, packet.nD0));
148 				break;
149 			case 0x07:
150 				//TEX0_2
151 				m_gs->WriteRegister(CGSHandler::RegisterWrite(GS_REG_TEX0_2, packet.nD0));
152 				break;
153 			case 0x08:
154 				//CLAMP_1
155 				m_gs->WriteRegister(CGSHandler::RegisterWrite(GS_REG_CLAMP_1, packet.nD0));
156 				break;
157 			case 0x09:
158 				//CLAMP_2
159 				m_gs->WriteRegister(CGSHandler::RegisterWrite(GS_REG_CLAMP_2, packet.nD0));
160 				break;
161 			case 0x0A:
162 				//FOG
163 				m_gs->WriteRegister(CGSHandler::RegisterWrite(GS_REG_FOG, (packet.nD1 >> 36) << 56));
164 				break;
165 			case 0x0D:
166 				//XYZ3
167 				m_gs->WriteRegister(CGSHandler::RegisterWrite(GS_REG_XYZ3, packet.nD0));
168 				break;
169 			case 0x0E:
170 				//A + D
171 				{
172 					uint8 reg = static_cast<uint8>(packet.nD1);
173 					if(reg == GS_REG_SIGNAL)
174 					{
175 						//Check if there's already a signal pending
176 						auto csr = m_gs->ReadPrivRegister(CGSHandler::GS_CSR);
177 						if((m_signalState == SIGNAL_STATE_ENCOUNTERED) || ((csr & CGSHandler::CSR_SIGNAL_EVENT) != 0))
178 						{
179 							//If there is, we need to wait for previous signal to be cleared
180 							m_signalState = SIGNAL_STATE_PENDING;
181 							return address - start;
182 						}
183 						m_signalState = SIGNAL_STATE_ENCOUNTERED;
184 					}
185 					m_gs->WriteRegister(CGSHandler::RegisterWrite(reg, packet.nD0));
186 				}
187 				break;
188 			case 0x0F:
189 				//NOP
190 				break;
191 			default:
192 				assert(0);
193 				break;
194 			}
195 
196 			address += 0x10;
197 			m_regsTemp--;
198 		}
199 
200 		if(m_regsTemp == 0)
201 		{
202 			m_loops--;
203 			m_regsTemp = m_regs;
204 		}
205 	}
206 
207 	return address - start;
208 }
209 
ProcessRegList(const uint8 * memory,uint32 address,uint32 end)210 uint32 CGIF::ProcessRegList(const uint8* memory, uint32 address, uint32 end)
211 {
212 	uint32 start = address;
213 
214 	while((m_loops != 0) && (address < end))
215 	{
216 		while((m_regsTemp != 0) && (address < end))
217 		{
218 			uint32 regDesc = (uint32)((m_regList >> ((m_regs - m_regsTemp) * 4)) & 0x0F);
219 			uint64 packet = *reinterpret_cast<const uint64*>(memory + address);
220 
221 			address += 0x08;
222 			m_regsTemp--;
223 
224 			if(regDesc == 0x0F) continue;
225 			m_gs->WriteRegister(CGSHandler::RegisterWrite(static_cast<uint8>(regDesc), packet));
226 		}
227 
228 		if(m_regsTemp == 0)
229 		{
230 			m_loops--;
231 			m_regsTemp = m_regs;
232 		}
233 	}
234 
235 	//Align on qword boundary
236 	if(address & 0x0F)
237 	{
238 		address += 8;
239 	}
240 
241 	return address - start;
242 }
243 
ProcessImage(const uint8 * memory,uint32 memorySize,uint32 address,uint32 end)244 uint32 CGIF::ProcessImage(const uint8* memory, uint32 memorySize, uint32 address, uint32 end)
245 {
246 	uint16 totalLoops = static_cast<uint16>((end - address) / 0x10);
247 	totalLoops = std::min<uint16>(totalLoops, m_loops);
248 
249 	//Some games like Dark Cloud 2 will execute a huge transfer that goes over the RAM size's limit
250 	//In that case, we split the transfer in half
251 	uint32 xferSize = totalLoops * 0x10;
252 	bool requiresSplit = (address + xferSize) > memorySize;
253 
254 	uint32 firstXferSize = requiresSplit ? (memorySize - address) : xferSize;
255 	m_gs->FeedImageData(memory + address, firstXferSize);
256 
257 	if(requiresSplit)
258 	{
259 		assert(xferSize > firstXferSize);
260 		m_gs->FeedImageData(memory, xferSize - firstXferSize);
261 	}
262 
263 	m_loops -= totalLoops;
264 
265 	return (totalLoops * 0x10);
266 }
267 
ProcessSinglePacket(const uint8 * memory,uint32 memorySize,uint32 address,uint32 end,const CGsPacketMetadata & packetMetadata)268 uint32 CGIF::ProcessSinglePacket(const uint8* memory, uint32 memorySize, uint32 address, uint32 end, const CGsPacketMetadata& packetMetadata)
269 {
270 #ifdef PROFILE
271 	CProfilerZone profilerZone(m_gifProfilerZone);
272 #endif
273 
274 #if defined(_DEBUG) && defined(DEBUGGER_INCLUDED)
275 	CLog::GetInstance().Print(LOG_NAME, "Received GIF packet on path %d at 0x%08X of 0x%08X bytes.\r\n",
276 	                          packetMetadata.pathIndex, address, end - address);
277 #endif
278 
279 	assert((m_activePath == 0) || (m_activePath == packetMetadata.pathIndex));
280 	m_signalState = SIGNAL_STATE_NONE;
281 
282 	uint32 start = address;
283 	while(address < end)
284 	{
285 		if(m_loops == 0)
286 		{
287 			if(m_eop)
288 			{
289 				m_eop = false;
290 				m_activePath = 0;
291 				break;
292 			}
293 
294 			//We need to update the registers
295 			auto tag = *reinterpret_cast<const TAG*>(&memory[address]);
296 			address += 0x10;
297 #ifdef _DEBUG
298 			CLog::GetInstance().Print(LOG_NAME, "TAG(loops = %d, eop = %d, pre = %d, prim = 0x%04X, cmd = %d, nreg = %d);\r\n",
299 			                          tag.loops, tag.eop, tag.pre, tag.prim, tag.cmd, tag.nreg);
300 #endif
301 
302 			m_loops = tag.loops;
303 			m_cmd = tag.cmd;
304 			m_regs = tag.nreg;
305 			m_regList = tag.regs;
306 			m_eop = (tag.eop != 0);
307 			m_qtemp = QTEMP_INIT;
308 
309 			if(m_cmd != 1)
310 			{
311 				if(tag.pre != 0)
312 				{
313 					m_gs->WriteRegister(CGSHandler::RegisterWrite(GS_REG_PRIM, static_cast<uint64>(tag.prim)));
314 				}
315 			}
316 
317 			if(m_regs == 0) m_regs = 0x10;
318 			m_regsTemp = m_regs;
319 			m_activePath = packetMetadata.pathIndex;
320 			continue;
321 		}
322 		switch(m_cmd)
323 		{
324 		case 0x00:
325 			address += ProcessPacked(memory, address, end);
326 			break;
327 		case 0x01:
328 			address += ProcessRegList(memory, address, end);
329 			break;
330 		case 0x02:
331 		case 0x03:
332 			//We need to flush our list here because image data can be embedded in a GIF packet
333 			//that specifies pixel transfer information in GS registers (and that has to be send first)
334 			//This is done by FFX
335 			m_gs->ProcessWriteBuffer(&packetMetadata);
336 			address += ProcessImage(memory, memorySize, address, end);
337 			break;
338 		}
339 
340 		if(m_signalState == SIGNAL_STATE_PENDING)
341 		{
342 			break;
343 		}
344 	}
345 
346 	if(m_loops == 0)
347 	{
348 		if(m_eop)
349 		{
350 			m_eop = false;
351 			m_activePath = 0;
352 		}
353 	}
354 
355 	m_gs->ProcessWriteBuffer(&packetMetadata);
356 
357 #ifdef _DEBUG
358 	CLog::GetInstance().Print(LOG_NAME, "Processed 0x%08X bytes.\r\n", address - start);
359 #endif
360 
361 	return address - start;
362 }
363 
ProcessMultiplePackets(const uint8 * memory,uint32 memorySize,uint32 address,uint32 end,const CGsPacketMetadata & packetMetadata)364 uint32 CGIF::ProcessMultiplePackets(const uint8* memory, uint32 memorySize, uint32 address, uint32 end, const CGsPacketMetadata& packetMetadata)
365 {
366 	//This will attempt to process everything from [address, end[ even if it contains multiple GIF packets
367 
368 	if((m_activePath != 0) && (m_activePath != packetMetadata.pathIndex))
369 	{
370 		//Packet transfer already active on a different path, we can't process this one
371 		return 0;
372 	}
373 
374 	uint32 start = address;
375 	while(address < end)
376 	{
377 		address += ProcessSinglePacket(memory, memorySize, address, end, packetMetadata);
378 		if(m_signalState == SIGNAL_STATE_PENDING)
379 		{
380 			//No point in continuing, GS won't accept any more data
381 			break;
382 		}
383 	}
384 	assert(address <= end);
385 	return address - start;
386 }
387 
ReceiveDMA(uint32 address,uint32 qwc,uint32 unused,bool tagIncluded)388 uint32 CGIF::ReceiveDMA(uint32 address, uint32 qwc, uint32 unused, bool tagIncluded)
389 {
390 	uint32 size = qwc * 0x10;
391 
392 	uint8* memory = nullptr;
393 	uint32 memorySize = 0;
394 	if(address & 0x80000000)
395 	{
396 		memory = m_spr;
397 		memorySize = PS2::EE_SPR_SIZE;
398 	}
399 	else
400 	{
401 		memory = m_ram;
402 		memorySize = PS2::EE_RAM_SIZE;
403 	}
404 
405 	address &= (memorySize - 1);
406 	assert((address + size) <= memorySize);
407 
408 	uint32 start = address;
409 	uint32 end = address + size;
410 
411 	if(tagIncluded)
412 	{
413 		assert(qwc >= 0);
414 		address += 0x10;
415 	}
416 
417 	address += ProcessMultiplePackets(memory, memorySize, address, end, CGsPacketMetadata(3));
418 	assert(address <= end);
419 
420 	return (address - start) / 0x10;
421 }
422 
GetRegister(uint32 address)423 uint32 CGIF::GetRegister(uint32 address)
424 {
425 	uint32 result = 0;
426 	switch(address)
427 	{
428 	case GIF_STAT:
429 		if(m_path3Masked)
430 		{
431 			result |= GIF_STAT_M3P;
432 			//Indicate that FIFO is full (15 qwords) (needed for GTA: San Andreas)
433 			result |= (0x1F << 24);
434 		}
435 
436 		result |= (m_gs->GetBUSDIR() << 12);
437 
438 		break;
439 	default:
440 		CLog::GetInstance().Warn(LOG_NAME, "Reading unknown register 0x%08X.\r\n", address);
441 		break;
442 	}
443 #ifdef _DEBUG
444 	DisassembleGet(address);
445 #endif
446 	return result;
447 }
448 
SetRegister(uint32 address,uint32 value)449 void CGIF::SetRegister(uint32 address, uint32 value)
450 {
451 #ifdef _DEBUG
452 	DisassembleSet(address, value);
453 #endif
454 }
455 
GetGsHandler()456 CGSHandler* CGIF::GetGsHandler()
457 {
458 	return m_gs;
459 }
460 
SetPath3Masked(bool masked)461 void CGIF::SetPath3Masked(bool masked)
462 {
463 	m_path3Masked = masked;
464 }
465 
DisassembleGet(uint32 address)466 void CGIF::DisassembleGet(uint32 address)
467 {
468 	switch(address)
469 	{
470 	case GIF_STAT:
471 		CLog::GetInstance().Print(LOG_NAME, "= GIF_STAT.\r\n", address);
472 		break;
473 	default:
474 		CLog::GetInstance().Warn(LOG_NAME, "Reading unknown register 0x%08X.\r\n", address);
475 		break;
476 	}
477 }
478 
DisassembleSet(uint32 address,uint32 value)479 void CGIF::DisassembleSet(uint32 address, uint32 value)
480 {
481 	switch(address)
482 	{
483 	default:
484 		CLog::GetInstance().Warn(LOG_NAME, "Writing unknown register 0x%08X, 0x%08X.\r\n", address, value);
485 		break;
486 	}
487 }
488