1 #include <cassert>
2 #include <cstring>
3 #include <climits>
4 #include <stdexcept>
5 #include "string_format.h"
6 #include "../Log.h"
7 #include "../Ps2Const.h"
8 #include "../states/RegisterStateFile.h"
9 #include "../states/MemoryStateFile.h"
10 #include "Vpu.h"
11 #include "Vif.h"
12 #include "INTC.h"
13 
14 #define LOG_NAME ("ee_vif")
15 
16 #define STATE_PATH_REGS_FORMAT ("vpu/vif_%d.xml")
17 #define STATE_PATH_FIFO_FORMAT ("vpu/vif_%d_fifo")
18 
19 #define STATE_REGS_STAT ("STAT")
20 #define STATE_REGS_CODE ("CODE")
21 #define STATE_REGS_CYCLE ("CYCLE")
22 #define STATE_REGS_NUM ("NUM")
23 #define STATE_REGS_MASK ("MASK")
24 #define STATE_REGS_MODE ("MODE")
25 #define STATE_REGS_ROW0 ("ROW0")
26 #define STATE_REGS_ROW1 ("ROW1")
27 #define STATE_REGS_ROW2 ("ROW2")
28 #define STATE_REGS_ROW3 ("ROW3")
29 #define STATE_REGS_COL0 ("COL0")
30 #define STATE_REGS_COL1 ("COL1")
31 #define STATE_REGS_COL2 ("COL2")
32 #define STATE_REGS_COL3 ("COL3")
33 #define STATE_REGS_MARK ("MARK")
34 #define STATE_REGS_ITOP ("ITOP")
35 #define STATE_REGS_ITOPS ("ITOPS")
36 #define STATE_REGS_READTICK ("readTick")
37 #define STATE_REGS_WRITETICK ("writeTick")
38 #define STATE_REGS_PENDINGMICROPROGRAM ("pendingMicroProgram")
39 #define STATE_REGS_FIFOINDEX ("fifoIndex")
40 #define STATE_REGS_INCOMINGFIFODELAY ("incomingFifoDelay")
41 
CVif(unsigned int number,CVpu & vpu,CINTC & intc,uint8 * ram,uint8 * spr)42 CVif::CVif(unsigned int number, CVpu& vpu, CINTC& intc, uint8* ram, uint8* spr)
43     : m_number(number)
44     , m_ram(ram)
45     , m_spr(spr)
46     , m_intc(intc)
47     , m_stream(ram, spr)
48     , m_vpu(vpu)
49     , m_vifProfilerZone(CProfiler::GetInstance().RegisterZone(string_format("VIF%d", number).c_str()))
50 {
51 }
52 
Reset()53 void CVif::Reset()
54 {
55 	memset(&m_STAT, 0, sizeof(STAT));
56 	memset(&m_CODE, 0, sizeof(CODE));
57 	memset(&m_CYCLE, 0, sizeof(CYCLE));
58 	memset(&m_R, 0, sizeof(m_R));
59 	memset(&m_C, 0, sizeof(m_C));
60 	memset(&m_fifoBuffer, 0, sizeof(m_fifoBuffer));
61 	m_CYCLE.nCL = 1;
62 	m_CYCLE.nWL = 1;
63 	m_fifoIndex = 0;
64 	m_MODE = 0;
65 	m_NUM = 0;
66 	m_MASK = 0;
67 	m_MARK = 0;
68 	m_ITOP = 0;
69 	m_ITOPS = 0;
70 	m_readTick = 0;
71 	m_writeTick = 0;
72 	m_stream.Reset();
73 	m_pendingMicroProgram = -1;
74 	m_incomingFifoDelay = 0;
75 }
76 
GetRegister(uint32 address)77 uint32 CVif::GetRegister(uint32 address)
78 {
79 	uint32 result = 0;
80 	switch(address)
81 	{
82 	case VIF0_STAT:
83 	case VIF1_STAT:
84 		result = m_STAT;
85 		if(m_STAT.nFDR != 0)
86 		{
87 			//When FDR is set, it usually means the game is trying to
88 			//read data from GS and that FIFO has some data in it
89 			//Set FQC (amount of quadwords in FIFO) to something to
90 			//let the game know the transfer is being executed
91 			//Games sensitive to this behavior:
92 			//- Serious Sam: Takes screen shots at checkpoints, waits for FQC to become 0
93 			//- PS2PSXe: Takes a screen shot of what is currently on screen, waits for FQC to become 0
94 			//- There are games that will check that it's not zero once FDR is set.
95 			result |= (m_incomingFifoDelay << 24);
96 			if(m_incomingFifoDelay != 0)
97 			{
98 				m_incomingFifoDelay--;
99 			}
100 		}
101 		break;
102 	case VIF0_ERR:
103 	case VIF1_ERR:
104 		result = m_ERR;
105 		break;
106 	case VIF0_MARK:
107 	case VIF1_MARK:
108 		result = m_MARK;
109 		break;
110 	case VIF0_CYCLE:
111 	case VIF1_CYCLE:
112 		result = m_CYCLE;
113 		break;
114 	case VIF0_MODE:
115 	case VIF1_MODE:
116 		result = m_MODE;
117 		break;
118 	case VIF0_NUM:
119 	case VIF1_NUM:
120 		result = m_NUM;
121 		break;
122 	case VIF0_MASK:
123 	case VIF1_MASK:
124 		result = m_MASK;
125 		break;
126 	case VIF0_CODE:
127 	case VIF1_CODE:
128 		result = m_CODE;
129 		break;
130 	case VIF0_R0:
131 	case VIF1_R0:
132 		result = m_R[0];
133 		break;
134 	case VIF0_R1:
135 	case VIF1_R1:
136 		result = m_R[1];
137 		break;
138 	case VIF0_R2:
139 	case VIF1_R2:
140 		result = m_R[2];
141 		break;
142 	case VIF0_R3:
143 	case VIF1_R3:
144 		result = m_R[3];
145 		break;
146 	default:
147 		CLog::GetInstance().Warn(LOG_NAME, "Reading unknown register 0x%08X.\r\n", address);
148 		break;
149 	}
150 #ifdef _DEBUG
151 	DisassembleGet(address);
152 #endif
153 	return result;
154 }
155 
SetRegister(uint32 address,uint32 value)156 void CVif::SetRegister(uint32 address, uint32 value)
157 {
158 	if(
159 	    (address >= VIF0_FIFO_START && address < VIF0_FIFO_END) ||
160 	    (address >= VIF1_FIFO_START && address < VIF1_FIFO_END))
161 	{
162 		ProcessFifoWrite(address, value);
163 	}
164 	else
165 	{
166 		switch(address)
167 		{
168 		case VIF1_STAT:
169 			m_STAT.nFDR = ((value & STAT_FDR) != 0) ? 1 : 0;
170 			if(m_STAT.nFDR)
171 			{
172 				m_incomingFifoDelay = 0x1F;
173 			}
174 			break;
175 		case VIF0_FBRST:
176 		case VIF1_FBRST:
177 			if(value & FBRST_RST)
178 			{
179 				//TODO: Reset FIFO
180 				m_CODE <<= 0;
181 				m_STAT <<= 0;
182 				m_NUM = 0;
183 			}
184 			if(value & FBRST_FBK || value & FBRST_STP)
185 			{
186 				// TODO: We need to properly handle this!
187 				// But I lack games which leverage it.
188 				assert(0);
189 			}
190 			if(value & FBRST_STC)
191 			{
192 				m_STAT.nVSS = 0;
193 				m_STAT.nVFS = 0;
194 				m_STAT.nVIS = 0;
195 				m_STAT.nINT = 0;
196 				m_STAT.nER0 = 0;
197 				m_STAT.nER1 = 0;
198 			}
199 			break;
200 		case VIF0_ERR:
201 		case VIF1_ERR:
202 			m_ERR <<= value;
203 			break;
204 		case VIF0_MARK:
205 		case VIF1_MARK:
206 			m_MARK = value;
207 			m_STAT.nMRK = 0;
208 			break;
209 		default:
210 			CLog::GetInstance().Warn(LOG_NAME, "Writing unknown register 0x%08X, 0x%08X.\r\n", address, value);
211 			break;
212 		}
213 	}
214 #ifdef _DEBUG
215 	DisassembleSet(address, value);
216 #endif
217 }
218 
SaveState(Framework::CZipArchiveWriter & archive)219 void CVif::SaveState(Framework::CZipArchiveWriter& archive)
220 {
221 	{
222 		auto path = string_format(STATE_PATH_REGS_FORMAT, m_number);
223 		auto registerFile = new CRegisterStateFile(path.c_str());
224 		registerFile->SetRegister32(STATE_REGS_STAT, m_STAT);
225 		registerFile->SetRegister32(STATE_REGS_CODE, m_CODE);
226 		registerFile->SetRegister32(STATE_REGS_CYCLE, m_CYCLE);
227 		registerFile->SetRegister32(STATE_REGS_NUM, m_NUM);
228 		registerFile->SetRegister32(STATE_REGS_MODE, m_MODE);
229 		registerFile->SetRegister32(STATE_REGS_MASK, m_MASK);
230 		registerFile->SetRegister32(STATE_REGS_MARK, m_MARK);
231 		registerFile->SetRegister32(STATE_REGS_ROW0, m_R[0]);
232 		registerFile->SetRegister32(STATE_REGS_ROW1, m_R[1]);
233 		registerFile->SetRegister32(STATE_REGS_ROW2, m_R[2]);
234 		registerFile->SetRegister32(STATE_REGS_ROW3, m_R[3]);
235 		registerFile->SetRegister32(STATE_REGS_COL0, m_C[0]);
236 		registerFile->SetRegister32(STATE_REGS_COL1, m_C[1]);
237 		registerFile->SetRegister32(STATE_REGS_COL2, m_C[2]);
238 		registerFile->SetRegister32(STATE_REGS_COL3, m_C[3]);
239 		registerFile->SetRegister32(STATE_REGS_ITOP, m_ITOP);
240 		registerFile->SetRegister32(STATE_REGS_ITOPS, m_ITOPS);
241 		registerFile->SetRegister32(STATE_REGS_READTICK, m_readTick);
242 		registerFile->SetRegister32(STATE_REGS_WRITETICK, m_writeTick);
243 		registerFile->SetRegister32(STATE_REGS_PENDINGMICROPROGRAM, m_pendingMicroProgram);
244 		registerFile->SetRegister32(STATE_REGS_FIFOINDEX, m_fifoIndex);
245 		registerFile->SetRegister32(STATE_REGS_INCOMINGFIFODELAY, m_incomingFifoDelay);
246 		archive.InsertFile(registerFile);
247 	}
248 	{
249 		auto path = string_format(STATE_PATH_FIFO_FORMAT, m_number);
250 		archive.InsertFile(new CMemoryStateFile(path.c_str(), &m_fifoBuffer, sizeof(m_fifoBuffer)));
251 	}
252 }
253 
LoadState(Framework::CZipArchiveReader & archive)254 void CVif::LoadState(Framework::CZipArchiveReader& archive)
255 {
256 	{
257 		auto path = string_format(STATE_PATH_REGS_FORMAT, m_number);
258 		CRegisterStateFile registerFile(*archive.BeginReadFile(path.c_str()));
259 		m_STAT <<= registerFile.GetRegister32(STATE_REGS_STAT);
260 		m_CODE <<= registerFile.GetRegister32(STATE_REGS_CODE);
261 		m_CYCLE <<= registerFile.GetRegister32(STATE_REGS_CYCLE);
262 		m_NUM = static_cast<uint8>(registerFile.GetRegister32(STATE_REGS_NUM));
263 		m_MODE = registerFile.GetRegister32(STATE_REGS_MODE);
264 		m_MASK = registerFile.GetRegister32(STATE_REGS_MASK);
265 		m_MARK = registerFile.GetRegister32(STATE_REGS_MARK);
266 		m_R[0] = registerFile.GetRegister32(STATE_REGS_ROW0);
267 		m_R[1] = registerFile.GetRegister32(STATE_REGS_ROW1);
268 		m_R[2] = registerFile.GetRegister32(STATE_REGS_ROW2);
269 		m_R[3] = registerFile.GetRegister32(STATE_REGS_ROW3);
270 		m_C[0] = registerFile.GetRegister32(STATE_REGS_COL0);
271 		m_C[1] = registerFile.GetRegister32(STATE_REGS_COL1);
272 		m_C[2] = registerFile.GetRegister32(STATE_REGS_COL2);
273 		m_C[3] = registerFile.GetRegister32(STATE_REGS_COL3);
274 		m_ITOP = registerFile.GetRegister32(STATE_REGS_ITOP);
275 		m_ITOPS = registerFile.GetRegister32(STATE_REGS_ITOPS);
276 		m_readTick = registerFile.GetRegister32(STATE_REGS_READTICK);
277 		m_writeTick = registerFile.GetRegister32(STATE_REGS_WRITETICK);
278 		m_pendingMicroProgram = registerFile.GetRegister32(STATE_REGS_PENDINGMICROPROGRAM);
279 		m_fifoIndex = registerFile.GetRegister32(STATE_REGS_FIFOINDEX);
280 		m_incomingFifoDelay = registerFile.GetRegister32(STATE_REGS_INCOMINGFIFODELAY);
281 	}
282 	{
283 		auto path = string_format(STATE_PATH_FIFO_FORMAT, m_number);
284 		archive.BeginReadFile(path.c_str())->Read(&m_fifoBuffer, sizeof(m_fifoBuffer));
285 	}
286 }
287 
GetTOP() const288 uint32 CVif::GetTOP() const
289 {
290 	throw std::exception();
291 }
292 
GetITOP() const293 uint32 CVif::GetITOP() const
294 {
295 	return m_ITOP;
296 }
297 
ReceiveDMA(uint32 address,uint32 qwc,uint32 unused,bool tagIncluded)298 uint32 CVif::ReceiveDMA(uint32 address, uint32 qwc, uint32 unused, bool tagIncluded)
299 {
300 	if(m_STAT.nVEW && m_vpu.IsVuRunning())
301 	{
302 		//Is waiting for program end, don't bother
303 		return 0;
304 	}
305 
306 #ifdef PROFILE
307 	CProfilerZone profilerZone(m_vifProfilerZone);
308 #endif
309 
310 #ifdef _DEBUG
311 	CLog::GetInstance().Print(LOG_NAME, "vif%i : Processing packet @ 0x%08X, qwc = 0x%X, tagIncluded = %i\r\n",
312 	                          m_number, address, qwc, static_cast<int>(tagIncluded));
313 #endif
314 
315 	m_stream.SetDmaParams(address, qwc * 0x10, tagIncluded);
316 
317 	ProcessPacket(m_stream);
318 
319 	uint32 remainingSize = m_stream.GetRemainingDmaTransferSize();
320 	assert((remainingSize & 0x0F) == 0);
321 	remainingSize /= 0x10;
322 
323 	return qwc - remainingSize;
324 }
325 
IsWaitingForProgramEnd() const326 bool CVif::IsWaitingForProgramEnd() const
327 {
328 	return (m_STAT.nVEW != 0);
329 }
330 
ProcessFifoWrite(uint32 address,uint32 value)331 void CVif::ProcessFifoWrite(uint32 address, uint32 value)
332 {
333 	assert(m_fifoIndex != FIFO_SIZE);
334 	if(m_fifoIndex == FIFO_SIZE)
335 	{
336 		return;
337 	}
338 	uint32 index = (address & 0xF) / 4;
339 	*reinterpret_cast<uint32*>(m_fifoBuffer + m_fifoIndex + index * 4) = value;
340 	if(index == 3)
341 	{
342 		m_fifoIndex += 0x10;
343 		m_stream.SetFifoParams(m_fifoBuffer, m_fifoIndex);
344 		ProcessPacket(m_stream);
345 		uint32 newIndex = m_stream.GetRemainingDmaTransferSize();
346 		uint32 discardSize = m_fifoIndex - newIndex;
347 		memmove(m_fifoBuffer, m_fifoBuffer + discardSize, newIndex);
348 		m_fifoIndex = newIndex;
349 	}
350 }
351 
ProcessPacket(StreamType & stream)352 void CVif::ProcessPacket(StreamType& stream)
353 {
354 	while(stream.GetAvailableReadBytes())
355 	{
356 		if(m_STAT.nVPS == 1)
357 		{
358 			//Command is waiting for more data...
359 			ExecuteCommand(stream, m_CODE);
360 
361 			if((m_STAT.nVPS == 1) && (stream.GetAvailableReadBytes() != 0))
362 			{
363 				//We have data in our FIFO but we still need more than what's available
364 				break;
365 			}
366 			else
367 			{
368 				continue;
369 			}
370 		}
371 		if(m_STAT.nVEW == 1)
372 		{
373 			if(m_vpu.IsVuRunning()) break;
374 			m_STAT.nVEW = 0;
375 			//Command is waiting for micro-program to end.
376 			ExecuteCommand(stream, m_CODE);
377 			continue;
378 		}
379 
380 		if(m_STAT.nVIS)
381 		{
382 			break;
383 		}
384 
385 		stream.Read(&m_CODE, sizeof(CODE));
386 
387 		if(m_CODE.nI != 0)
388 		{
389 			//Next command will be stalled (if not MARK)
390 			if(m_CODE.nCMD != CODE_CMD_MARK)
391 			{
392 				m_STAT.nVIS = 1;
393 			}
394 			m_STAT.nINT = 1;
395 			m_intc.AssertLine(CINTC::INTC_LINE_VIF0 + m_number);
396 		}
397 
398 		m_NUM = m_CODE.nNUM;
399 
400 		ExecuteCommand(stream, m_CODE);
401 	}
402 
403 	if(stream.GetAvailableReadBytes() == 0)
404 	{
405 		ResumeDelayedMicroProgram();
406 	}
407 }
408 
ExecuteCommand(StreamType & stream,CODE nCommand)409 void CVif::ExecuteCommand(StreamType& stream, CODE nCommand)
410 {
411 #ifdef _DEBUG
412 	if(m_number == 0)
413 	{
414 		DisassembleCommand(nCommand);
415 	}
416 #endif
417 	if(nCommand.nCMD >= 0x60)
418 	{
419 		Cmd_UNPACK(stream, nCommand, (nCommand.nIMM & 0x03FF));
420 		return;
421 	}
422 	switch(nCommand.nCMD)
423 	{
424 	case 0:
425 		//NOP
426 		break;
427 	case 0x01:
428 		//STCYCL
429 		m_CYCLE <<= nCommand.nIMM;
430 		break;
431 	case 0x04:
432 		//ITOP
433 		if(ResumeDelayedMicroProgram())
434 		{
435 			m_STAT.nVEW = 1;
436 			return;
437 		}
438 		m_ITOPS = nCommand.nIMM & 0x3FF;
439 		break;
440 	case 0x05:
441 		//STMOD
442 		m_MODE = nCommand.nIMM & 0x03;
443 		break;
444 	case CODE_CMD_MARK:
445 		m_MARK = nCommand.nIMM;
446 		m_STAT.nMRK = 1;
447 		break;
448 	case 0x10:
449 		//FLUSHE
450 		if(m_vpu.IsVuRunning())
451 		{
452 			m_STAT.nVEW = 1;
453 		}
454 		else
455 		{
456 			m_STAT.nVEW = 0;
457 		}
458 		if(ResumeDelayedMicroProgram())
459 		{
460 			m_STAT.nVEW = 1;
461 			return;
462 		}
463 		break;
464 	case 0x14:
465 		//MSCAL
466 		if(ResumeDelayedMicroProgram())
467 		{
468 			m_STAT.nVEW = 1;
469 			return;
470 		}
471 		StartDelayedMicroProgram(nCommand.nIMM * 8);
472 		break;
473 	case 0x15:
474 		//MSCALF
475 		//TODO: Wait for GIF PATH 1 and 2 transfers to be over
476 		if(ResumeDelayedMicroProgram())
477 		{
478 			m_STAT.nVEW = 1;
479 			return;
480 		}
481 		StartMicroProgram(nCommand.nIMM * 8);
482 		break;
483 	case 0x17:
484 		//MSCNT
485 		if(ResumeDelayedMicroProgram())
486 		{
487 			m_STAT.nVEW = 1;
488 			return;
489 		}
490 		StartMicroProgram(m_vpu.GetContext().m_State.nPC);
491 		break;
492 	case 0x20:
493 		//STMASK
494 		Cmd_STMASK(stream, nCommand);
495 		break;
496 	case 0x30:
497 		//STROW
498 		Cmd_STROW(stream, nCommand);
499 		break;
500 	case 0x31:
501 		//STCOL
502 		Cmd_STCOL(stream, nCommand);
503 		break;
504 	case 0x4A:
505 		//MPG
506 		Cmd_MPG(stream, nCommand);
507 		break;
508 	default:
509 		CLog::GetInstance().Warn(LOG_NAME, "Executed invalid command %d.\r\n", nCommand.nCMD);
510 		m_STAT.nER1 = 1;
511 		break;
512 	}
513 }
514 
Cmd_MPG(StreamType & stream,CODE nCommand)515 void CVif::Cmd_MPG(StreamType& stream, CODE nCommand)
516 {
517 	uint32 nSize = stream.GetAvailableReadBytes();
518 
519 	uint32 nNum = (m_NUM == 0) ? (256) : (m_NUM);
520 	uint32 nCodeNum = (m_CODE.nNUM == 0) ? (256) : (m_CODE.nNUM);
521 	uint32 nTransfered = (nCodeNum - nNum) * 8;
522 
523 	nCodeNum *= 8;
524 	nNum *= 8;
525 
526 	nSize = std::min<uint32>(nNum, nSize);
527 
528 	uint32 nDstAddr = (m_CODE.nIMM * 8) + nTransfered;
529 	nDstAddr &= (m_vpu.GetMicroMemorySize() - 1);
530 
531 	//Check if microprogram is running
532 	if(m_vpu.IsVuRunning())
533 	{
534 		m_STAT.nVEW = 1;
535 		return;
536 	}
537 
538 	if(nSize != 0)
539 	{
540 		auto microMem = m_vpu.GetMicroMemory();
541 		auto copyToMicroMem =
542 		    [&](const uint8* microProgramPtr, uint32 start, uint32 size) {
543 			    //Check if there's a change
544 			    if(memcmp(microMem + start, microProgramPtr, size) != 0)
545 			    {
546 				    m_vpu.InvalidateMicroProgram(start, start + size);
547 				    memcpy(microMem + start, microProgramPtr, size);
548 			    }
549 		    };
550 
551 		uint8* microProgram = reinterpret_cast<uint8*>(alloca(nSize));
552 		stream.Read(microProgram, nSize);
553 
554 		assert(nSize <= m_vpu.GetMicroMemorySize());
555 
556 		//Check if the copy's destination address will wrap around
557 		if((nDstAddr + nSize) > m_vpu.GetMicroMemorySize())
558 		{
559 			uint32 start1 = nDstAddr;
560 			uint32 size1 = m_vpu.GetMicroMemorySize() - nDstAddr;
561 
562 			uint32 start2 = 0;
563 			uint32 size2 = nSize - size1;
564 
565 			copyToMicroMem(microProgram, start1, size1);
566 			copyToMicroMem(microProgram + size1, start2, size2);
567 		}
568 		else
569 		{
570 			copyToMicroMem(microProgram, nDstAddr, nSize);
571 		}
572 	}
573 
574 	m_NUM -= static_cast<uint8>(nSize / 8);
575 	if((m_NUM == 0) && (nSize != 0))
576 	{
577 		m_STAT.nVPS = 0;
578 	}
579 	else
580 	{
581 		m_STAT.nVPS = 1;
582 	}
583 }
584 
Cmd_STROW(StreamType & stream,CODE nCommand)585 void CVif::Cmd_STROW(StreamType& stream, CODE nCommand)
586 {
587 	if(m_NUM == 0)
588 	{
589 		m_NUM = 4;
590 	}
591 
592 	while(m_NUM != 0 && stream.GetAvailableReadBytes())
593 	{
594 		assert(m_NUM <= 4);
595 		stream.Read(&m_R[4 - m_NUM], 4);
596 		m_NUM--;
597 	}
598 
599 	if(m_NUM == 0)
600 	{
601 		m_STAT.nVPS = 0;
602 	}
603 	else
604 	{
605 		m_STAT.nVPS = 1;
606 	}
607 }
608 
Cmd_STCOL(StreamType & stream,CODE nCommand)609 void CVif::Cmd_STCOL(StreamType& stream, CODE nCommand)
610 {
611 	if(m_NUM == 0)
612 	{
613 		m_NUM = 4;
614 	}
615 
616 	while(m_NUM != 0 && stream.GetAvailableReadBytes())
617 	{
618 		assert(m_NUM <= 4);
619 		stream.Read(&m_C[4 - m_NUM], 4);
620 		m_NUM--;
621 	}
622 
623 	if(m_NUM == 0)
624 	{
625 		m_STAT.nVPS = 0;
626 	}
627 	else
628 	{
629 		m_STAT.nVPS = 1;
630 	}
631 }
632 
Cmd_STMASK(StreamType & stream,CODE command)633 void CVif::Cmd_STMASK(StreamType& stream, CODE command)
634 {
635 	if(m_NUM == 0)
636 	{
637 		m_NUM = 1;
638 	}
639 
640 	while(m_NUM != 0 && stream.GetAvailableReadBytes())
641 	{
642 		stream.Read(&m_MASK, 4);
643 		m_NUM--;
644 	}
645 
646 	if(m_NUM == 0)
647 	{
648 		m_STAT.nVPS = 0;
649 	}
650 	else
651 	{
652 		m_STAT.nVPS = 1;
653 	}
654 }
655 
Cmd_UNPACK(StreamType & stream,CODE nCommand,uint32 nDstAddr)656 void CVif::Cmd_UNPACK(StreamType& stream, CODE nCommand, uint32 nDstAddr)
657 {
658 	assert((nCommand.nCMD & 0x60) == 0x60);
659 
660 	const auto vuMem = m_vpu.GetVuMemory();
661 	const auto vuMemSize = m_vpu.GetVuMemorySize();
662 	bool usn = (m_CODE.nIMM & 0x4000) != 0;
663 	bool useMask = (nCommand.nCMD & 0x10) != 0;
664 	uint32 cl = m_CYCLE.nCL;
665 	uint32 wl = m_CYCLE.nWL;
666 	if(wl == 0)
667 	{
668 		wl = UINT_MAX;
669 		cl = 0;
670 	}
671 
672 	if(m_NUM == nCommand.nNUM)
673 	{
674 		m_readTick = 0;
675 		m_writeTick = 0;
676 	}
677 
678 	uint32 currentNum = (m_NUM == 0) ? 256 : m_NUM;
679 	uint32 codeNum = (m_CODE.nNUM == 0) ? 256 : m_CODE.nNUM;
680 	uint32 transfered = codeNum - currentNum;
681 
682 	if(cl > wl)
683 	{
684 		nDstAddr += cl * (transfered / wl) + (transfered % wl);
685 	}
686 	else
687 	{
688 		nDstAddr += transfered;
689 	}
690 
691 	nDstAddr *= 0x10;
692 	assert(nDstAddr < vuMemSize);
693 	nDstAddr &= (vuMemSize - 1);
694 
695 	while(currentNum != 0)
696 	{
697 		bool mustWrite = false;
698 		uint128 writeValue;
699 		memset(&writeValue, 0, sizeof(writeValue));
700 
701 		if(cl >= wl)
702 		{
703 			if(m_readTick < wl)
704 			{
705 				bool success = Unpack_ReadValue(nCommand, stream, writeValue, usn);
706 				if(!success) break;
707 				mustWrite = true;
708 			}
709 		}
710 		else
711 		{
712 			if(m_writeTick < cl)
713 			{
714 				bool success = Unpack_ReadValue(nCommand, stream, writeValue, usn);
715 				if(!success) break;
716 			}
717 
718 			mustWrite = true;
719 		}
720 
721 		if(mustWrite)
722 		{
723 			auto dst = reinterpret_cast<uint128*>(vuMem + nDstAddr);
724 
725 			for(unsigned int i = 0; i < 4; i++)
726 			{
727 				uint32 maskOp = useMask ? GetMaskOp(i, m_writeTick) : MASK_DATA;
728 
729 				if(maskOp == MASK_DATA)
730 				{
731 					if(m_MODE == MODE_OFFSET)
732 					{
733 						writeValue.nV[i] += m_R[i];
734 					}
735 					else if(m_MODE == MODE_DIFFERENCE)
736 					{
737 						writeValue.nV[i] += m_R[i];
738 						m_R[i] = writeValue.nV[i];
739 					}
740 
741 					dst->nV[i] = writeValue.nV[i];
742 				}
743 				else if(maskOp == MASK_ROW)
744 				{
745 					dst->nV[i] = m_R[i];
746 				}
747 				else if(maskOp == MASK_COL)
748 				{
749 					int index = (m_writeTick > 3) ? 3 : m_writeTick;
750 					dst->nV[i] = m_C[index];
751 				}
752 				else if(maskOp == MASK_MASK)
753 				{
754 					//Don't write anything
755 				}
756 				else
757 				{
758 					assert(0);
759 				}
760 			}
761 
762 			currentNum--;
763 		}
764 
765 		if(cl >= wl)
766 		{
767 			m_writeTick = std::min<uint32>(m_writeTick + 1, wl);
768 			m_readTick = std::min<uint32>(m_readTick + 1, cl);
769 
770 			if(m_readTick == cl)
771 			{
772 				m_writeTick = 0;
773 				m_readTick = 0;
774 			}
775 		}
776 		else
777 		{
778 			m_writeTick = std::min<uint32>(m_writeTick + 1, wl);
779 			m_readTick = std::min<uint32>(m_readTick + 1, cl);
780 
781 			if(m_writeTick == wl)
782 			{
783 				m_writeTick = 0;
784 				m_readTick = 0;
785 			}
786 		}
787 
788 		nDstAddr += 0x10;
789 		nDstAddr &= (vuMemSize - 1);
790 	}
791 
792 	if(currentNum != 0)
793 	{
794 		m_STAT.nVPS = 1;
795 	}
796 	else
797 	{
798 		stream.Align32();
799 		m_STAT.nVPS = 0;
800 	}
801 
802 	m_NUM = static_cast<uint8>(currentNum);
803 }
804 
Unpack_ReadValue(const CODE & nCommand,StreamType & stream,uint128 & writeValue,bool usn)805 bool CVif::Unpack_ReadValue(const CODE& nCommand, StreamType& stream, uint128& writeValue, bool usn)
806 {
807 	bool success = false;
808 	switch(nCommand.nCMD & 0x0F)
809 	{
810 	case 0x00:
811 		//S-32
812 		success = Unpack_S32(stream, writeValue);
813 		break;
814 	case 0x01:
815 		//S-16
816 		success = Unpack_S16(stream, writeValue, usn);
817 		break;
818 	case 0x02:
819 		//S-8
820 		success = Unpack_S8(stream, writeValue, usn);
821 		break;
822 	case 0x04:
823 		//V2-32
824 		success = Unpack_V32(stream, writeValue, 2);
825 		break;
826 	case 0x05:
827 		//V2-16
828 		success = Unpack_V16(stream, writeValue, 2, usn);
829 		break;
830 	case 0x06:
831 		//V2-8
832 		success = Unpack_V8(stream, writeValue, 2, usn);
833 		break;
834 	case 0x08:
835 		//V3-32
836 		success = Unpack_V32(stream, writeValue, 3);
837 		break;
838 	case 0x09:
839 		//V3-16
840 		success = Unpack_V16(stream, writeValue, 3, usn);
841 		break;
842 	case 0x0A:
843 		//V3-8
844 		success = Unpack_V8(stream, writeValue, 3, usn);
845 		break;
846 	case 0x0C:
847 		//V4-32
848 		success = Unpack_V32(stream, writeValue, 4);
849 		break;
850 	case 0x0D:
851 		//V4-16
852 		success = Unpack_V16(stream, writeValue, 4, usn);
853 		break;
854 	case 0x0E:
855 		//V4-8
856 		success = Unpack_V8(stream, writeValue, 4, usn);
857 		break;
858 	case 0x0F:
859 		//V4-5
860 		success = Unpack_V45(stream, writeValue);
861 		break;
862 	default:
863 		assert(0);
864 		break;
865 	}
866 	return success;
867 }
868 
Unpack_S32(StreamType & stream,uint128 & result)869 bool CVif::Unpack_S32(StreamType& stream, uint128& result)
870 {
871 	if(stream.GetAvailableReadBytes() < 4) return false;
872 
873 	uint32 word = 0;
874 	stream.Read(&word, 4);
875 
876 	for(unsigned int i = 0; i < 4; i++)
877 	{
878 		result.nV[i] = word;
879 	}
880 
881 	return true;
882 }
883 
Unpack_S16(StreamType & stream,uint128 & result,bool zeroExtend)884 bool CVif::Unpack_S16(StreamType& stream, uint128& result, bool zeroExtend)
885 {
886 	if(stream.GetAvailableReadBytes() < 2) return false;
887 
888 	uint32 temp = 0;
889 	stream.Read(&temp, 2);
890 	if(!zeroExtend)
891 	{
892 		temp = static_cast<int16>(temp);
893 	}
894 
895 	for(unsigned int i = 0; i < 4; i++)
896 	{
897 		result.nV[i] = temp;
898 	}
899 
900 	return true;
901 }
902 
Unpack_S8(StreamType & stream,uint128 & result,bool zeroExtend)903 bool CVif::Unpack_S8(StreamType& stream, uint128& result, bool zeroExtend)
904 {
905 	if(stream.GetAvailableReadBytes() < 1) return false;
906 
907 	uint32 temp = 0;
908 	stream.Read(&temp, 1);
909 	if(!zeroExtend)
910 	{
911 		temp = static_cast<int8>(temp);
912 	}
913 
914 	for(unsigned int i = 0; i < 4; i++)
915 	{
916 		result.nV[i] = temp;
917 	}
918 
919 	return true;
920 }
921 
Unpack_V8(StreamType & stream,uint128 & result,unsigned int fields,bool zeroExtend)922 bool CVif::Unpack_V8(StreamType& stream, uint128& result, unsigned int fields, bool zeroExtend)
923 {
924 	if(stream.GetAvailableReadBytes() < (fields)) return false;
925 
926 	for(unsigned int i = 0; i < fields; i++)
927 	{
928 		uint32 temp = 0;
929 		stream.Read(&temp, 1);
930 		if(!zeroExtend)
931 		{
932 			temp = static_cast<int8>(temp);
933 		}
934 
935 		result.nV[i] = temp;
936 	}
937 
938 	return true;
939 }
940 
Unpack_V16(StreamType & stream,uint128 & result,unsigned int fields,bool zeroExtend)941 bool CVif::Unpack_V16(StreamType& stream, uint128& result, unsigned int fields, bool zeroExtend)
942 {
943 	if(stream.GetAvailableReadBytes() < (fields * 2)) return false;
944 
945 	for(unsigned int i = 0; i < fields; i++)
946 	{
947 		uint32 temp = 0;
948 		stream.Read(&temp, 2);
949 		if(!zeroExtend)
950 		{
951 			temp = static_cast<int16>(temp);
952 		}
953 
954 		result.nV[i] = temp;
955 	}
956 
957 	return true;
958 }
959 
Unpack_V32(StreamType & stream,uint128 & result,unsigned int fields)960 bool CVif::Unpack_V32(StreamType& stream, uint128& result, unsigned int fields)
961 {
962 	if(stream.GetAvailableReadBytes() < (fields * 4)) return false;
963 
964 	stream.Read(&result, (fields * 4));
965 
966 	return true;
967 }
968 
Unpack_V45(StreamType & stream,uint128 & result)969 bool CVif::Unpack_V45(StreamType& stream, uint128& result)
970 {
971 	if(stream.GetAvailableReadBytes() < 2) return false;
972 
973 	uint16 nColor = 0;
974 	stream.Read(&nColor, 2);
975 
976 	result.nV0 = ((nColor >> 0) & 0x1F) << 3;
977 	result.nV1 = ((nColor >> 5) & 0x1F) << 3;
978 	result.nV2 = ((nColor >> 10) & 0x1F) << 3;
979 	result.nV3 = ((nColor >> 15) & 0x01) << 7;
980 
981 	return true;
982 }
983 
GetMaskOp(unsigned int row,unsigned int col) const984 uint32 CVif::GetMaskOp(unsigned int row, unsigned int col) const
985 {
986 	if(col > 3) col = 3;
987 	assert(row < 4);
988 	unsigned int index = (col * 4) + row;
989 	return (m_MASK >> (index * 2)) & 0x03;
990 }
991 
PrepareMicroProgram()992 void CVif::PrepareMicroProgram()
993 {
994 	m_ITOP = m_ITOPS;
995 }
996 
StartMicroProgram(uint32 address)997 void CVif::StartMicroProgram(uint32 address)
998 {
999 	if(m_vpu.IsVuRunning())
1000 	{
1001 		m_STAT.nVEW = 1;
1002 		return;
1003 	}
1004 
1005 	assert(!m_STAT.nVEW);
1006 	PrepareMicroProgram();
1007 	m_vpu.ExecuteMicroProgram(address);
1008 }
1009 
StartDelayedMicroProgram(uint32 address)1010 void CVif::StartDelayedMicroProgram(uint32 address)
1011 {
1012 	//Snowblind Studio games start a VU microprogram and issues an UNPACK command
1013 	//which has data needed by the microprogram. We simulate the microprogram
1014 	//starting a bit later to let the UNPACK command execute
1015 	if(m_vpu.IsVuRunning())
1016 	{
1017 		m_STAT.nVEW = 1;
1018 		return;
1019 	}
1020 
1021 	assert(!m_STAT.nVEW);
1022 	PrepareMicroProgram();
1023 	m_pendingMicroProgram = address;
1024 }
1025 
ResumeDelayedMicroProgram()1026 bool CVif::ResumeDelayedMicroProgram()
1027 {
1028 	if(m_pendingMicroProgram != -1)
1029 	{
1030 		assert(!IsWaitingForProgramEnd());
1031 		assert(!m_vpu.IsVuRunning());
1032 		m_vpu.ExecuteMicroProgram(m_pendingMicroProgram);
1033 		m_pendingMicroProgram = -1;
1034 		return true;
1035 	}
1036 	else
1037 	{
1038 		return false;
1039 	}
1040 }
1041 
DisassembleGet(uint32 address)1042 void CVif::DisassembleGet(uint32 address)
1043 {
1044 #define LOG_GET(registerId)                                            \
1045 	case registerId:                                                   \
1046 		CLog::GetInstance().Print(LOG_NAME, "= " #registerId ".\r\n"); \
1047 		break;
1048 
1049 	switch(address)
1050 	{
1051 		LOG_GET(VIF0_STAT)
1052 		LOG_GET(VIF0_ERR)
1053 		LOG_GET(VIF0_MARK)
1054 		LOG_GET(VIF0_CYCLE)
1055 		LOG_GET(VIF0_MODE)
1056 		LOG_GET(VIF0_NUM)
1057 		LOG_GET(VIF0_MASK)
1058 		LOG_GET(VIF0_CODE)
1059 		LOG_GET(VIF0_R0)
1060 		LOG_GET(VIF0_R1)
1061 		LOG_GET(VIF0_R2)
1062 		LOG_GET(VIF0_R3)
1063 
1064 		LOG_GET(VIF1_STAT)
1065 		LOG_GET(VIF1_ERR)
1066 		LOG_GET(VIF1_MARK)
1067 		LOG_GET(VIF1_CYCLE)
1068 		LOG_GET(VIF1_MODE)
1069 		LOG_GET(VIF1_NUM)
1070 		LOG_GET(VIF1_MASK)
1071 		LOG_GET(VIF1_CODE)
1072 		LOG_GET(VIF1_R0)
1073 		LOG_GET(VIF1_R1)
1074 		LOG_GET(VIF1_R2)
1075 		LOG_GET(VIF1_R3)
1076 
1077 	default:
1078 		CLog::GetInstance().Print(LOG_NAME, "Reading unknown register 0x%08X.\r\n", address);
1079 		break;
1080 	}
1081 
1082 #undef LOG_GET
1083 }
1084 
DisassembleSet(uint32 address,uint32 value)1085 void CVif::DisassembleSet(uint32 address, uint32 value)
1086 {
1087 	if((address >= VIF0_FIFO_START) && (address < VIF0_FIFO_END))
1088 	{
1089 		CLog::GetInstance().Print(LOG_NAME, "VIF0_FIFO(0x%03X) = 0x%08X.\r\n", address & 0xFFF, value);
1090 	}
1091 	else if((address >= VIF1_FIFO_START) && (address < VIF1_FIFO_END))
1092 	{
1093 		CLog::GetInstance().Print(LOG_NAME, "VIF1_FIFO(0x%03X) = 0x%08X.\r\n", address & 0xFFF, value);
1094 	}
1095 	else
1096 	{
1097 #define LOG_SET(registerId)                                                       \
1098 	case registerId:                                                              \
1099 		CLog::GetInstance().Print(LOG_NAME, #registerId " = 0x%08X.\r\n", value); \
1100 		break;
1101 
1102 		switch(address)
1103 		{
1104 			LOG_SET(VIF0_FBRST)
1105 			LOG_SET(VIF0_MARK)
1106 			LOG_SET(VIF0_ERR)
1107 
1108 			LOG_SET(VIF1_FBRST)
1109 			LOG_SET(VIF1_MARK)
1110 			LOG_SET(VIF1_ERR)
1111 
1112 		default:
1113 			CLog::GetInstance().Print(LOG_NAME, "Writing unknown register 0x%08X, 0x%08X.\r\n", address, value);
1114 			break;
1115 		}
1116 
1117 #undef LOG_SET
1118 	}
1119 }
1120 
DisassembleCommand(CODE code)1121 void CVif::DisassembleCommand(CODE code)
1122 {
1123 	if(m_STAT.nVPS != 0) return;
1124 
1125 	CLog::GetInstance().Print(LOG_NAME, "vif%i : ", m_number);
1126 
1127 	if(code.nI)
1128 	{
1129 		CLog::GetInstance().Print(LOG_NAME, "(I) ");
1130 	}
1131 
1132 	if(code.nCMD >= 0x60)
1133 	{
1134 		static const char* packFormats[16] =
1135 		    {
1136 		        "S-32",
1137 		        "S-16",
1138 		        "S-8",
1139 		        "(Unknown)",
1140 		        "V2-32",
1141 		        "V2-16",
1142 		        "V2-8",
1143 		        "(Unknown)",
1144 		        "V3-32",
1145 		        "V3-16",
1146 		        "V3-8",
1147 		        "(Unknown)",
1148 		        "V4-32",
1149 		        "V4-16",
1150 		        "V4-8",
1151 		        "V4-5"};
1152 		CLog::GetInstance().Print(LOG_NAME, "UNPACK(format = %s, imm = 0x%x, num = 0x%x);\r\n",
1153 		                          packFormats[code.nCMD & 0x0F], code.nIMM, code.nNUM);
1154 	}
1155 	else
1156 	{
1157 		switch(code.nCMD)
1158 		{
1159 		case 0x00:
1160 			CLog::GetInstance().Print(LOG_NAME, "NOP\r\n");
1161 			break;
1162 		case 0x01:
1163 			CLog::GetInstance().Print(LOG_NAME, "STCYCL(imm = 0x%x);\r\n", code.nIMM);
1164 			break;
1165 		case 0x02:
1166 			CLog::GetInstance().Print(LOG_NAME, "OFFSET(imm = 0x%x);\r\n", code.nIMM);
1167 			break;
1168 		case 0x03:
1169 			CLog::GetInstance().Print(LOG_NAME, "BASE(imm = 0x%x);\r\n", code.nIMM);
1170 			break;
1171 		case 0x04:
1172 			CLog::GetInstance().Print(LOG_NAME, "ITOP(imm = 0x%x);\r\n", code.nIMM);
1173 			break;
1174 		case 0x05:
1175 			CLog::GetInstance().Print(LOG_NAME, "STMOD(imm = 0x%x);\r\n", code.nIMM);
1176 			break;
1177 		case 0x06:
1178 			CLog::GetInstance().Print(LOG_NAME, "MSKPATH3(mask = %d);\r\n", (code.nIMM & 0x8000) ? 1 : 0);
1179 			break;
1180 		case 0x07:
1181 			CLog::GetInstance().Print(LOG_NAME, "MARK(imm = 0x%x);\r\n", code.nIMM);
1182 			break;
1183 		case 0x10:
1184 			CLog::GetInstance().Print(LOG_NAME, "FLUSHE();\r\n");
1185 			break;
1186 		case 0x11:
1187 			CLog::GetInstance().Print(LOG_NAME, "FLUSH();\r\n");
1188 			break;
1189 		case 0x13:
1190 			CLog::GetInstance().Print(LOG_NAME, "FLUSHA();\r\n");
1191 			break;
1192 		case 0x14:
1193 			CLog::GetInstance().Print(LOG_NAME, "MSCAL(imm = 0x%x);\r\n", code.nIMM);
1194 			break;
1195 		case 0x15:
1196 			CLog::GetInstance().Print(LOG_NAME, "MSCALF(imm = 0x%x);\r\n", code.nIMM);
1197 			break;
1198 		case 0x17:
1199 			CLog::GetInstance().Print(LOG_NAME, "MSCNT();\r\n");
1200 			break;
1201 		case 0x20:
1202 			CLog::GetInstance().Print(LOG_NAME, "STMASK();\r\n");
1203 			break;
1204 		case 0x30:
1205 			CLog::GetInstance().Print(LOG_NAME, "STROW();\r\n");
1206 			break;
1207 		case 0x31:
1208 			CLog::GetInstance().Print(LOG_NAME, "STCOL();\r\n");
1209 			break;
1210 		case 0x4A:
1211 			CLog::GetInstance().Print(LOG_NAME, "MPG(imm = 0x%x, num = 0x%x);\r\n", code.nIMM, code.nNUM);
1212 			break;
1213 		case 0x50:
1214 			CLog::GetInstance().Print(LOG_NAME, "DIRECT(imm = 0x%x);\r\n", code.nIMM);
1215 			break;
1216 		case 0x51:
1217 			CLog::GetInstance().Print(LOG_NAME, "DIRECTHL(imm = 0x%x);\r\n", code.nIMM);
1218 			break;
1219 		default:
1220 			CLog::GetInstance().Print(LOG_NAME, "Unknown command (0x%x).\r\n", code.nCMD);
1221 			break;
1222 		}
1223 	}
1224 }
1225 
1226 //CFifoStream
1227 //--------------------------------------------------
1228 
CFifoStream(uint8 * ram,uint8 * spr)1229 CVif::CFifoStream::CFifoStream(uint8* ram, uint8* spr)
1230     : m_ram(ram)
1231     , m_spr(spr)
1232 {
1233 }
1234 
Reset()1235 void CVif::CFifoStream::Reset()
1236 {
1237 	m_bufferPosition = BUFFERSIZE;
1238 	m_startAddress = 0;
1239 	m_nextAddress = 0;
1240 	m_endAddress = 0;
1241 	m_tagIncluded = false;
1242 	m_source = nullptr;
1243 }
1244 
Read(void * buffer,uint32 size)1245 void CVif::CFifoStream::Read(void* buffer, uint32 size)
1246 {
1247 	assert(m_source != NULL);
1248 	uint8* readBuffer = reinterpret_cast<uint8*>(buffer);
1249 	while(size != 0)
1250 	{
1251 		SyncBuffer();
1252 		uint32 read = std::min<uint32>(size, BUFFERSIZE - m_bufferPosition);
1253 		if(readBuffer != NULL)
1254 		{
1255 			memcpy(readBuffer, reinterpret_cast<uint8*>(&m_buffer) + m_bufferPosition, read);
1256 			readBuffer += read;
1257 		}
1258 		m_bufferPosition += read;
1259 		size -= read;
1260 	}
1261 }
1262 
Flush()1263 void CVif::CFifoStream::Flush()
1264 {
1265 	m_bufferPosition = BUFFERSIZE;
1266 }
1267 
SetDmaParams(uint32 address,uint32 size,bool tagIncluded)1268 void CVif::CFifoStream::SetDmaParams(uint32 address, uint32 size, bool tagIncluded)
1269 {
1270 	if(address & 0x80000000)
1271 	{
1272 		m_source = m_spr;
1273 		address &= (PS2::EE_SPR_SIZE - 1);
1274 		assert((address + size) <= PS2::EE_SPR_SIZE);
1275 	}
1276 	else
1277 	{
1278 		m_source = m_ram;
1279 		address &= (PS2::EE_RAM_SIZE - 1);
1280 		assert((address + size) <= PS2::EE_RAM_SIZE);
1281 	}
1282 	m_startAddress = address;
1283 	m_nextAddress = address;
1284 	m_endAddress = address + size;
1285 	m_tagIncluded = tagIncluded;
1286 	SyncBuffer();
1287 }
1288 
SetFifoParams(uint8 * source,uint32 size)1289 void CVif::CFifoStream::SetFifoParams(uint8* source, uint32 size)
1290 {
1291 	m_source = source;
1292 	m_startAddress = 0;
1293 	m_nextAddress = 0;
1294 	m_endAddress = size;
1295 	m_tagIncluded = false;
1296 	SyncBuffer();
1297 }
1298 
GetAvailableReadBytes() const1299 uint32 CVif::CFifoStream::GetAvailableReadBytes() const
1300 {
1301 	return GetRemainingDmaTransferSize() + (BUFFERSIZE - m_bufferPosition);
1302 }
1303 
GetRemainingDmaTransferSize() const1304 uint32 CVif::CFifoStream::GetRemainingDmaTransferSize() const
1305 {
1306 	return m_endAddress - m_nextAddress;
1307 }
1308 
Align32()1309 void CVif::CFifoStream::Align32()
1310 {
1311 	unsigned int remainBytes = m_bufferPosition & 0x03;
1312 	if(remainBytes == 0) return;
1313 	Read(NULL, 4 - remainBytes);
1314 	assert((m_bufferPosition & 0x03) == 0);
1315 }
1316 
GetDirectPointer() const1317 uint8* CVif::CFifoStream::GetDirectPointer() const
1318 {
1319 	assert(!m_tagIncluded);
1320 	if(m_bufferPosition == BUFFERSIZE)
1321 	{
1322 		return m_source + m_nextAddress;
1323 	}
1324 	else
1325 	{
1326 		assert((m_nextAddress - m_startAddress) >= 0x10);
1327 		return m_source + m_nextAddress + m_bufferPosition - 0x10;
1328 	}
1329 }
1330 
Advance(uint32 size)1331 void CVif::CFifoStream::Advance(uint32 size)
1332 {
1333 	assert((size & 0x0F) == 0);
1334 	assert(!m_tagIncluded);
1335 	//If buffer was untouched, we can do as if we read from it directly
1336 	if(m_bufferPosition == 0)
1337 	{
1338 		assert(size >= 0x10);
1339 		size -= 0x10;
1340 		m_bufferPosition = BUFFERSIZE;
1341 	}
1342 	assert((m_nextAddress + size) <= m_endAddress);
1343 	m_nextAddress += size;
1344 	if(m_bufferPosition != BUFFERSIZE)
1345 	{
1346 		//Update buffer
1347 		assert((m_nextAddress - m_startAddress) >= 0x10);
1348 		m_buffer = *reinterpret_cast<uint128*>(&m_source[m_nextAddress - 0x10]);
1349 	}
1350 }
1351 
SyncBuffer()1352 void CVif::CFifoStream::SyncBuffer()
1353 {
1354 	assert(m_bufferPosition <= BUFFERSIZE);
1355 	if(m_bufferPosition >= BUFFERSIZE)
1356 	{
1357 		if(m_nextAddress >= m_endAddress)
1358 		{
1359 			throw std::exception();
1360 		}
1361 		m_buffer = *reinterpret_cast<uint128*>(&m_source[m_nextAddress]);
1362 		m_nextAddress += 0x10;
1363 		m_bufferPosition = 0;
1364 		if(m_tagIncluded)
1365 		{
1366 			//Skip next 8 bytes
1367 			m_tagIncluded = false;
1368 			m_bufferPosition += 8;
1369 		}
1370 	}
1371 }
1372