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