| 
									
										
										
										
											2013-04-17 23:29:41 -04:00
										 |  |  | // Copyright 2013 Dolphin Emulator Project
 | 
					
						
							|  |  |  | // Licensed under GPLv2
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "Common/Atomic.h"
 | 
					
						
							|  |  |  | #include "Common/ChunkFile.h"
 | 
					
						
							|  |  |  | #include "Common/Common.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-20 04:11:52 +01:00
										 |  |  | #include "Common/FPURoundMode.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "Common/MathUtil.h"
 | 
					
						
							|  |  |  | #include "Common/Thread.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "Core/ConfigManager.h"
 | 
					
						
							|  |  |  | #include "Core/Core.h"
 | 
					
						
							|  |  |  | #include "Core/CoreTiming.h"
 | 
					
						
							|  |  |  | #include "Core/HW/Memmap.h"
 | 
					
						
							|  |  |  | #include "Core/HW/MMIO.h"
 | 
					
						
							|  |  |  | #include "Core/HW/ProcessorInterface.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "VideoBackends/Software/OpcodeDecoder.h"
 | 
					
						
							|  |  |  | #include "VideoBackends/Software/SWCommandProcessor.h"
 | 
					
						
							|  |  |  | #include "VideoBackends/Software/VideoBackend.h"
 | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-08 16:49:33 +02:00
										 |  |  | #include "VideoCommon/DataReader.h"
 | 
					
						
							|  |  |  | #include "VideoCommon/Fifo.h"
 | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-03 19:55:30 +00:00
										 |  |  | namespace SWCommandProcessor | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	GATHER_PIPE_SIZE = 32, | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 	INT_CAUSE_CP =  0x800 | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // STATE_TO_SAVE
 | 
					
						
							|  |  |  | // variables
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-08 15:58:25 +02:00
										 |  |  | static const int commandBufferSize = 1024 * 1024; | 
					
						
							|  |  |  | static const int maxCommandBufferWrite = commandBufferSize - GATHER_PIPE_SIZE; | 
					
						
							|  |  |  | static u8 commandBuffer[commandBufferSize]; | 
					
						
							|  |  |  | static u32 readPos; | 
					
						
							|  |  |  | static u32 writePos; | 
					
						
							|  |  |  | static int et_UpdateInterrupts; | 
					
						
							|  |  |  | static volatile bool interruptSet; | 
					
						
							|  |  |  | static volatile bool interruptWaiting; | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-08 22:37:58 +02:00
										 |  |  | static CPReg cpreg; // shared between gfx and emulator thread
 | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | void DoState(PointerWrap &p) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-04-09 18:57:39 -05:00
										 |  |  | 	p.DoPOD(cpreg); | 
					
						
							| 
									
										
										
										
											2013-02-25 23:49:24 -05:00
										 |  |  | 	p.DoArray(commandBuffer, commandBufferSize); | 
					
						
							| 
									
										
										
										
											2013-02-25 20:05:02 -05:00
										 |  |  | 	p.Do(readPos); | 
					
						
							|  |  |  | 	p.Do(writePos); | 
					
						
							|  |  |  | 	p.Do(et_UpdateInterrupts); | 
					
						
							|  |  |  | 	p.Do(interruptSet); | 
					
						
							|  |  |  | 	p.Do(interruptWaiting); | 
					
						
							| 
									
										
										
										
											2013-02-25 23:49:24 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Is this right?
 | 
					
						
							|  |  |  | 	p.DoArray(g_pVideoData,writePos); | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // does it matter that there is no synchronization between threads during writes?
 | 
					
						
							| 
									
										
										
										
											2014-08-10 21:51:05 -04:00
										 |  |  | static inline void WriteLow (u32& _reg, u16 lowbits) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	_reg = (_reg & 0xFFFF0000) | lowbits; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | static inline void WriteHigh(u32& _reg, u16 highbits) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	_reg = (_reg & 0x0000FFFF) | ((u32)highbits << 16); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-10 21:51:05 -04:00
										 |  |  | static inline u16 ReadLow(u32 _reg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return (u16)(_reg & 0xFFFF); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | static inline u16 ReadHigh(u32 _reg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return (u16)(_reg >> 16); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-08 14:29:26 +02:00
										 |  |  | static void UpdateInterrupts_Wrapper(u64 userdata, int cyclesLate) | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	UpdateInterrupts(userdata); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-10 21:51:05 -04:00
										 |  |  | static inline bool AtBreakpoint() | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 	return cpreg.ctrl.BPEnable && (cpreg.readptr == cpreg.breakpt); | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Init() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 	cpreg.status.Hex = 0; | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 	cpreg.status.CommandIdle = 1; | 
					
						
							|  |  |  | 	cpreg.status.ReadIdle = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 	cpreg.ctrl.Hex = 0; | 
					
						
							|  |  |  | 	cpreg.clear.Hex = 0; | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	cpreg.bboxleft = 0; | 
					
						
							|  |  |  | 	cpreg.bboxtop  = 0; | 
					
						
							|  |  |  | 	cpreg.bboxright = 0; | 
					
						
							|  |  |  | 	cpreg.bboxbottom = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cpreg.token = 0; | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-31 01:28:32 +00:00
										 |  |  | 	et_UpdateInterrupts = CoreTiming::RegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper); | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 	// internal buffer position
 | 
					
						
							|  |  |  | 	readPos = 0; | 
					
						
							|  |  |  | 	writePos = 0; | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 	interruptSet = false; | 
					
						
							|  |  |  | 	interruptWaiting = false; | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | 	g_pVideoData = nullptr; | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 	g_bSkipCurrentFrame = false; | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Shutdown() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RunGpu() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 	if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		// We are going to do FP math on the main thread so have to save the current state
 | 
					
						
							|  |  |  | 		FPURoundMode::SaveSIMDState(); | 
					
						
							|  |  |  | 		FPURoundMode::LoadDefaultSIMDState(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// run the opcode decoder
 | 
					
						
							|  |  |  | 		do | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			RunBuffer(); | 
					
						
							|  |  |  | 		} while (cpreg.ctrl.GPReadEnable && !AtBreakpoint() && cpreg.readptr != cpreg.writeptr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		FPURoundMode::LoadSIMDState(); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-04 01:09:57 +01:00
										 |  |  | void RegisterMMIO(MMIO::Mapping* mmio, u32 base) | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-02-04 01:09:57 +01:00
										 |  |  | 	// Directly map reads and writes to the cpreg structure.
 | 
					
						
							|  |  |  | 	for (size_t i = 0; i < sizeof (cpreg) / sizeof (u16); ++i) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		u16* ptr = ((u16*)&cpreg) + i; | 
					
						
							|  |  |  | 		mmio->Register(base | (i * 2), | 
					
						
							|  |  |  | 			MMIO::DirectRead<u16>(ptr), | 
					
						
							|  |  |  | 			MMIO::DirectWrite<u16>(ptr) | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-04 01:09:57 +01:00
										 |  |  | 	// Bleh. Apparently SWCommandProcessor does not know about regs 0x40 to
 | 
					
						
							|  |  |  | 	// 0x64...
 | 
					
						
							|  |  |  | 	for (size_t i = 0x40; i < 0x64; ++i) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		mmio->Register(base | i, | 
					
						
							|  |  |  | 			MMIO::Constant<u16>(0), | 
					
						
							|  |  |  | 			MMIO::Nop<u16>() | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-04 01:09:57 +01:00
										 |  |  | 	// The low part of MMIO regs for FIFO addresses needs to be aligned to 32
 | 
					
						
							|  |  |  | 	// bytes.
 | 
					
						
							|  |  |  | 	u32 fifo_addr_lo_regs[] = { | 
					
						
							| 
									
										
										
										
											2014-06-16 13:17:32 -07:00
										 |  |  | 		CommandProcessor::FIFO_BASE_LO, | 
					
						
							|  |  |  | 		CommandProcessor::FIFO_END_LO, | 
					
						
							|  |  |  | 		CommandProcessor::FIFO_WRITE_POINTER_LO, | 
					
						
							|  |  |  | 		CommandProcessor::FIFO_READ_POINTER_LO, | 
					
						
							|  |  |  | 		CommandProcessor::FIFO_BP_LO, | 
					
						
							|  |  |  | 		CommandProcessor::FIFO_RW_DISTANCE_LO, | 
					
						
							| 
									
										
										
										
											2014-02-04 01:09:57 +01:00
										 |  |  | 	}; | 
					
						
							|  |  |  | 	for (u32 reg : fifo_addr_lo_regs) | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-02-04 01:09:57 +01:00
										 |  |  | 		mmio->RegisterWrite(base | reg, | 
					
						
							|  |  |  | 			MMIO::DirectWrite<u16>(((u16*)&cpreg) + (reg / 2), 0xFFE0) | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-04 01:09:57 +01:00
										 |  |  | 	// The clear register needs to perform some more complicated operations on
 | 
					
						
							|  |  |  | 	// writes.
 | 
					
						
							| 
									
										
										
										
											2014-06-16 13:17:32 -07:00
										 |  |  | 	mmio->RegisterWrite(base | CommandProcessor::CLEAR_REGISTER, | 
					
						
							| 
									
										
										
										
											2014-02-04 01:09:57 +01:00
										 |  |  | 		MMIO::ComplexWrite<u16>([](u32, u16 val) { | 
					
						
							|  |  |  | 			UCPClearReg tmpClear(val); | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 			if (tmpClear.ClearFifoOverflow) | 
					
						
							|  |  |  | 				cpreg.status.OverflowHiWatermark = 0; | 
					
						
							|  |  |  | 			if (tmpClear.ClearFifoUnderflow) | 
					
						
							|  |  |  | 				cpreg.status.UnderflowLoWatermark = 0; | 
					
						
							| 
									
										
										
										
											2014-02-04 01:09:57 +01:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | void STACKALIGN GatherPipeBursted() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (cpreg.ctrl.GPLinkEnable) | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		DEBUG_LOG(COMMANDPROCESSOR,"\t WGP burst. write thru : %08x", cpreg.writeptr); | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 		if (cpreg.writeptr == cpreg.fifoend) | 
					
						
							|  |  |  | 			cpreg.writeptr = cpreg.fifobase; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			cpreg.writeptr += GATHER_PIPE_SIZE; | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 		Common::AtomicAdd(cpreg.rwdistance, GATHER_PIPE_SIZE); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 	RunGpu(); | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void UpdateInterrupts(u64 userdata) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 	if (userdata) | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		interruptSet = true; | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 		INFO_LOG(COMMANDPROCESSOR,"Interrupt set"); | 
					
						
							|  |  |  | 		ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true); | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 		interruptSet = false; | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 		INFO_LOG(COMMANDPROCESSOR,"Interrupt cleared"); | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 		ProcessorInterface::SetInterrupt(INT_CAUSE_CP, false); | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 	interruptWaiting = false; | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-14 02:18:03 +00:00
										 |  |  | void UpdateInterruptsFromVideoBackend(u64 userdata) | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-01-31 01:28:32 +00:00
										 |  |  | 	CoreTiming::ScheduleEvent_Threadsafe(0, et_UpdateInterrupts, userdata); | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-08 14:29:26 +02:00
										 |  |  | static void ReadFifo() | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 	bool canRead = cpreg.readptr != cpreg.writeptr && writePos < (int)maxCommandBufferWrite; | 
					
						
							|  |  |  | 	bool atBreakpoint = AtBreakpoint(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (canRead && !atBreakpoint) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		// read from fifo
 | 
					
						
							|  |  |  | 		u8 *ptr = Memory::GetPointer(cpreg.readptr); | 
					
						
							|  |  |  | 		int bytesRead = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		do | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			// copy to buffer
 | 
					
						
							|  |  |  | 			memcpy(&commandBuffer[writePos], ptr, GATHER_PIPE_SIZE); | 
					
						
							|  |  |  | 			writePos += GATHER_PIPE_SIZE; | 
					
						
							|  |  |  | 			bytesRead += GATHER_PIPE_SIZE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (cpreg.readptr == cpreg.fifoend) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				cpreg.readptr = cpreg.fifobase; | 
					
						
							|  |  |  | 				ptr = Memory::GetPointer(cpreg.readptr); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				cpreg.readptr += GATHER_PIPE_SIZE; | 
					
						
							|  |  |  | 				ptr += GATHER_PIPE_SIZE; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			canRead = cpreg.readptr != cpreg.writeptr && writePos < (int)maxCommandBufferWrite; | 
					
						
							|  |  |  | 			atBreakpoint = AtBreakpoint(); | 
					
						
							|  |  |  | 		} while (canRead && !atBreakpoint); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		Common::AtomicAdd(cpreg.rwdistance, -bytesRead); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-08 14:29:26 +02:00
										 |  |  | static void SetStatus() | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 	// overflow check
 | 
					
						
							|  |  |  | 	if (cpreg.rwdistance > cpreg.hiwatermark) | 
					
						
							|  |  |  | 		cpreg.status.OverflowHiWatermark = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// underflow check
 | 
					
						
							|  |  |  | 	if (cpreg.rwdistance < cpreg.lowatermark) | 
					
						
							|  |  |  | 		cpreg.status.UnderflowLoWatermark = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// breakpoint
 | 
					
						
							|  |  |  | 	if (cpreg.ctrl.BPEnable) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if (cpreg.breakpt == cpreg.readptr) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			if (!cpreg.status.Breakpoint) | 
					
						
							|  |  |  | 				INFO_LOG(COMMANDPROCESSOR, "Hit breakpoint at %x", cpreg.readptr); | 
					
						
							|  |  |  | 			cpreg.status.Breakpoint = 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if (cpreg.status.Breakpoint) | 
					
						
							|  |  |  | 			INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %x", cpreg.readptr); | 
					
						
							|  |  |  | 		cpreg.status.Breakpoint = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cpreg.status.ReadIdle = cpreg.readptr == cpreg.writeptr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-16 13:17:32 -07:00
										 |  |  | 	bool bpInt = cpreg.status.Breakpoint && cpreg.ctrl.BPInt; | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 	bool ovfInt = cpreg.status.OverflowHiWatermark && cpreg.ctrl.FifoOverflowIntEnable; | 
					
						
							|  |  |  | 	bool undfInt = cpreg.status.UnderflowLoWatermark && cpreg.ctrl.FifoUnderflowIntEnable; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool interrupt = bpInt || ovfInt || undfInt; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (interrupt != interruptSet && !interruptWaiting) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		u64 userdata = interrupt?1:0; | 
					
						
							|  |  |  | 		if (SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			interruptWaiting = true; | 
					
						
							|  |  |  | 			SWCommandProcessor::UpdateInterruptsFromVideoBackend(userdata); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			SWCommandProcessor::UpdateInterrupts(userdata); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool RunBuffer() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 	// fifo is read 32 bytes at a time
 | 
					
						
							|  |  |  | 	// read fifo data to internal buffer
 | 
					
						
							|  |  |  | 	if (cpreg.ctrl.GPReadEnable) | 
					
						
							|  |  |  | 		ReadFifo(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	SetStatus(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_dbg_assert_(COMMANDPROCESSOR, writePos >= readPos); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	g_pVideoData = &commandBuffer[readPos]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	u32 availableBytes = writePos - readPos; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (OpcodeDecoder::CommandRunnable(availableBytes)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		cpreg.status.CommandIdle = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		OpcodeDecoder::Run(availableBytes); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// if data was read by the opcode decoder then the video data pointer changed
 | 
					
						
							|  |  |  | 		readPos = (u32)(g_pVideoData - &commandBuffer[0]); | 
					
						
							|  |  |  | 		_dbg_assert_(VIDEO, writePos >= readPos); | 
					
						
							|  |  |  | 		availableBytes = writePos - readPos; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cpreg.status.CommandIdle = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool ranDecoder = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-19 09:21:45 -04:00
										 |  |  | 	// move data remaining in the command buffer
 | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 	if (readPos > 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		memmove(&commandBuffer[0], &commandBuffer[readPos], availableBytes); | 
					
						
							|  |  |  | 		writePos -= readPos; | 
					
						
							|  |  |  | 		readPos = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ranDecoder = true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ranDecoder; | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-16 22:48:17 +00:00
										 |  |  | void SetRendering(bool enabled) | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-04-13 23:54:02 -04:00
										 |  |  | 	g_bSkipCurrentFrame = !enabled; | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-16 22:48:17 +00:00
										 |  |  | } // end of namespace SWCommandProcessor
 | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 |