// Copyright 2008 Dolphin Emulator Project // Licensed under GPLv2+ // Refer to the license.txt file included. #include #include "Common/ChunkFile.h" #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" #include "Core/HW/GPFifo.h" #include "Core/HW/Memmap.h" #include "Core/HW/ProcessorInterface.h" #include "Core/PowerPC/JitInterface.h" #include "VideoCommon/CommandProcessor.h" namespace GPFifo { // 32 Byte gather pipe with extra space // Overfilling is no problem (up to the real limit), CheckGatherPipe will blast the // contents in nicely sized chunks // // Other optimizations to think about: // - If the GP is NOT linked to the FIFO, just blast to memory byte by word // - If the GP IS linked to the FIFO, use a fast wrapping buffer and skip writing to memory // // Both of these should actually work! Only problem is that we have to decide at run time, // the same function could use both methods. Compile 2 different versions of each such block? // More room for the fastmodes alignas(32) u8 m_gatherPipe[GATHER_PIPE_SIZE * 16]; // pipe counter u32 m_gatherPipeCount = 0; void DoState(PointerWrap& p) { p.Do(m_gatherPipe); p.Do(m_gatherPipeCount); } void Init() { ResetGatherPipe(); memset(m_gatherPipe, 0, sizeof(m_gatherPipe)); } bool IsEmpty() { return m_gatherPipeCount == 0; } void ResetGatherPipe() { m_gatherPipeCount = 0; } static void UpdateGatherPipe() { u32 cnt; u8* curMem = Memory::GetPointer(ProcessorInterface::Fifo_CPUWritePointer); for (cnt = 0; m_gatherPipeCount >= GATHER_PIPE_SIZE; cnt += GATHER_PIPE_SIZE) { // copy the GatherPipe memcpy(curMem, m_gatherPipe + cnt, GATHER_PIPE_SIZE); m_gatherPipeCount -= GATHER_PIPE_SIZE; // increase the CPUWritePointer if (ProcessorInterface::Fifo_CPUWritePointer == ProcessorInterface::Fifo_CPUEnd) { ProcessorInterface::Fifo_CPUWritePointer = ProcessorInterface::Fifo_CPUBase; curMem = Memory::GetPointer(ProcessorInterface::Fifo_CPUWritePointer); } else { curMem += GATHER_PIPE_SIZE; ProcessorInterface::Fifo_CPUWritePointer += GATHER_PIPE_SIZE; } CommandProcessor::GatherPipeBursted(); } // move back the spill bytes memmove(m_gatherPipe, m_gatherPipe + cnt, m_gatherPipeCount); } void FastCheckGatherPipe() { if (m_gatherPipeCount >= GATHER_PIPE_SIZE) { UpdateGatherPipe(); } } void CheckGatherPipe() { if (m_gatherPipeCount >= GATHER_PIPE_SIZE) { UpdateGatherPipe(); // Profile where slow FIFO writes are occurring. JitInterface::CompileExceptionCheck(JitInterface::ExceptionType::EXCEPTIONS_FIFO_WRITE); } } void Write8(const u8 value) { FastWrite8(value); CheckGatherPipe(); } void Write16(const u16 value) { FastWrite16(value); CheckGatherPipe(); } void Write32(const u32 value) { FastWrite32(value); CheckGatherPipe(); } void Write64(const u64 value) { FastWrite64(value); CheckGatherPipe(); } void FastWrite8(const u8 value) { m_gatherPipe[m_gatherPipeCount] = value; ++m_gatherPipeCount; } void FastWrite16(u16 value) { value = Common::swap16(value); std::memcpy(&m_gatherPipe[m_gatherPipeCount], &value, sizeof(u16)); m_gatherPipeCount += sizeof(u16); } void FastWrite32(u32 value) { value = Common::swap32(value); std::memcpy(&m_gatherPipe[m_gatherPipeCount], &value, sizeof(u32)); m_gatherPipeCount += sizeof(u32); } void FastWrite64(u64 value) { value = Common::swap64(value); std::memcpy(&m_gatherPipe[m_gatherPipeCount], &value, sizeof(u64)); m_gatherPipeCount += sizeof(u64); } } // end of namespace GPFifo