From 337ff1f56b752198076a67049c85edf3a37af078 Mon Sep 17 00:00:00 2001 From: "memberTwo.mb2" Date: Thu, 20 Nov 2008 12:16:51 +0000 Subject: [PATCH] More GPFifo works. PEToken management as I think it should be. Super Monkey Ball Adventures fix (the token check loop was stuck in one JITed block without any Advance() call). git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1224 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Core/Src/HW/CommandProcessor.cpp | 31 ++++++++----- Source/Core/Core/Src/HW/PixelEngine.cpp | 48 ++++++++++++++------ Source/PluginSpecs/pluginspecs_video.h | 6 ++- 3 files changed, 58 insertions(+), 27 deletions(-) diff --git a/Source/Core/Core/Src/HW/CommandProcessor.cpp b/Source/Core/Core/Src/HW/CommandProcessor.cpp index 2dd1440cce..4d9b1e54cb 100644 --- a/Source/Core/Core/Src/HW/CommandProcessor.cpp +++ b/Source/Core/Core/Src/HW/CommandProcessor.cpp @@ -25,6 +25,10 @@ // - ZTP: seems to use PEfinish only // - Animal Crossing: PEfinish at start but there's a bug... // There's tons of HiWmk/LoWmk ping pong -> Another sync fashion? +// - Super Monkey Ball Adventures: PEToken. Oddity: read&check-PEToken-value-loop stays +// in its JITed block (never fall in Advance() until the game-watchdog's stuff). +// That's why we can't let perform the AdvanceCallBack as usual. +// The PEToken is volatile now and in the fifo struct. // *What I guess (thx to asynchronous DualCore mode): // PPC have a frame-finish watchdog. Handled by system timming stuff like the decrementer. @@ -144,6 +148,7 @@ int m_bboxbottom; u16 m_tokenReg; SCPFifoStruct fifo; //This one is shared between gfx thread and emulator thread +static u32 fake_GPWatchdogLastToken = 0; void DoState(PointerWrap &p) { @@ -181,15 +186,10 @@ void IncrementGPWDToken() // Check every FAKE_GP_WATCHDOG_PERIOD if a PE-frame-finish occured // if not then lock CPUThread until GP finish a frame. -u32 fake_GPWatchdogLastToken = 0; void WaitForFrameFinish() { - while (fake_GPWatchdogLastToken == fifo.Fake_GPWDToken && fifo.bFF_GPReadEnable && (fifo.CPReadWriteDistance > 0) && !(fifo.bFF_BPEnable && fifo.bFF_Breakpoint)) + while ((fake_GPWatchdogLastToken == fifo.Fake_GPWDToken) && fifo.bFF_GPReadEnable && (fifo.CPReadWriteDistance > 0) && !(fifo.bFF_BPEnable && fifo.bFF_Breakpoint)) ; - // oh well, should be safe. - // Assuming: time between 2 GP-frame-finish (ie. increment of fifo.Fake_GPWDToken) - // will be EVER way superior to time between - // "while (g_FAKE_GPWatchdogToken == fifo.Fake_GPWDToken..." and this line. :p fake_GPWatchdogLastToken = fifo.Fake_GPWDToken; } @@ -217,9 +217,10 @@ void Init() fifo.bFF_GPReadEnable = FALSE; fifo.bFF_GPLinkEnable = FALSE; fifo.bFF_BPEnable = FALSE; + fifo.PEToken = 0; // for GP watchdog hack - fifo.Fake_GPWDInterrupt = FALSE; fifo.Fake_GPWDToken = 0; + fake_GPWatchdogLastToken = 0; et_UpdateInterrupts = CoreTiming::RegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper); } @@ -376,7 +377,7 @@ void Write16(const u16 _Value, const u32 _Address) // update interrupts UpdateInterrupts(); - LOG(COMMANDPROCESSOR,"write to STATUS_REGISTER : %04x", _Value); + LOG(COMMANDPROCESSOR,"\t write to STATUS_REGISTER : %04x", _Value); } break; @@ -413,14 +414,16 @@ void Write16(const u16 _Value, const u32 _Address) } }/**/ UpdateInterrupts(); - LOG(COMMANDPROCESSOR, "\t GPREAD %s | CPULINK %s | BP %s || CPIntEnable %s" + LOG(COMMANDPROCESSOR,"\t write to CTRL_REGISTER : %04x", _Value); + LOG(COMMANDPROCESSOR, "\t GPREAD %s | CPULINK %s | BP %s || CPIntEnable %s | OvF %s | UndF %s" , fifo.bFF_GPReadEnable ? "ON" : "OFF" , fifo.bFF_GPLinkEnable ? "ON" : "OFF" , fifo.bFF_BPEnable ? "ON" : "OFF" , m_CPCtrlReg.CPIntEnable ? "ON" : "OFF" + , m_CPCtrlReg.FifoOverflowIntEnable ? "ON" : "OFF" + , m_CPCtrlReg.FifoUnderflowIntEnable ? "ON" : "OFF" ); - LOG(COMMANDPROCESSOR,"write to CTRL_REGISTER : %04x", _Value); } break; @@ -429,12 +432,15 @@ void Write16(const u16 _Value, const u32 _Address) UCPClearReg tmpClearReg(_Value); m_CPClearReg.Hex = 0; - LOG(COMMANDPROCESSOR,"write to CLEAR_REGISTER : %04x",_Value); + LOG(COMMANDPROCESSOR,"\t write to CLEAR_REGISTER : %04x",_Value); } break; // Fifo Registers - case FIFO_TOKEN_REGISTER: m_tokenReg = _Value; break; + case FIFO_TOKEN_REGISTER: + m_tokenReg = _Value; + LOG(COMMANDPROCESSOR,"write to FIFO_TOKEN_REGISTER : %04x", _Value); + break; case FIFO_BASE_LO: WriteLow ((u32 &)fifo.CPBase, _Value); fifo.CPBase &= 0xFFFFFFE0; break; case FIFO_BASE_HI: WriteHigh((u32 &)fifo.CPBase, _Value); fifo.CPBase &= 0xFFFFFFE0; break; @@ -543,6 +549,7 @@ void GatherPipeBursted() // - CPU can write to fifo // - disable Underflow interrupt + LOG(COMMANDPROCESSOR, "(GatherPipeBursted): CPHiWatermark reached"); // Wait for GPU to catch up //while (!(fifo.bFF_BPEnable && fifo.bFF_Breakpoint) && fifo.CPReadWriteDistance > (s32)fifo.CPLoWatermark) while (fifo.CPReadWriteDistance > fifo.CPLoWatermark) diff --git a/Source/Core/Core/Src/HW/PixelEngine.cpp b/Source/Core/Core/Src/HW/PixelEngine.cpp index 71fbcff764..54d193033e 100644 --- a/Source/Core/Core/Src/HW/PixelEngine.cpp +++ b/Source/Core/Core/Src/HW/PixelEngine.cpp @@ -55,7 +55,6 @@ union UPECtrlReg // STATE_TO_SAVE static UPECtrlReg g_ctrlReg; -static u16 g_token = 0; static bool g_bSignalTokenInterrupt; static bool g_bSignalFinishInterrupt; @@ -66,7 +65,7 @@ int et_SetFinishOnMainThread; void DoState(PointerWrap &p) { p.Do(g_ctrlReg); - p.Do(g_token); + p.Do(CommandProcessor::fifo.PEToken); p.Do(g_bSignalTokenInterrupt); p.Do(g_bSignalFinishInterrupt); } @@ -78,7 +77,6 @@ void SetFinish_OnMainThread(u64 userdata, int cyclesLate); void Init() { - g_token = 0; g_ctrlReg.Hex = 0; et_SetTokenOnMainThread = CoreTiming::RegisterEvent("SetToken", SetToken_OnMainThread); @@ -93,10 +91,12 @@ void Read16(u16& _uReturnValue, const u32 _iAddress) { case CTRL_REGISTER: _uReturnValue = g_ctrlReg.Hex; + LOG(PIXELENGINE,"\t CTRL_REGISTER : %04x", _uReturnValue); return; case TOKEN_REG: - _uReturnValue = g_token; + _uReturnValue = CommandProcessor::fifo.PEToken; + LOG(PIXELENGINE,"\t TOKEN_REG : %04x", _uReturnValue); return; default: @@ -135,9 +135,10 @@ void Write16(const u16 _iValue, const u32 _iAddress) break; case TOKEN_REG: - LOG(PIXELENGINE,"WEIRD: program wrote token: %i",_iValue); + //LOG(PIXELENGINE,"WEIRD: program wrote token: %i",_iValue); + PanicAlert("PIXELENGINE : (w16) WTF? program wrote token: %i",_iValue); //only the gx pipeline is supposed to be able to write here - g_token = _iValue; + //g_token = _iValue; break; } } @@ -162,15 +163,19 @@ void UpdateInterrupts() CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_PE_FINISH, false); } +// TODO(mb2): Refactor SetTokenINT_OnMainThread(u64 userdata, int cyclesLate). Cleanup++ +// Called only if BPMEM_PE_TOKEN_INT_ID is ack by GP void SetToken_OnMainThread(u64 userdata, int cyclesLate) { - // In the future: schedule callback that does the rest of this function - // This way we will be threadsafe - if (userdata >> 16) + //if (userdata >> 16) + //{ g_bSignalTokenInterrupt = true; - g_token = (u16)(userdata & 0xFFFF); - LOGV(PIXELENGINE, 1, "VIDEO Plugin wrote token: %i", g_token); - UpdateInterrupts(); + _dbg_assert_msg_(PIXELENGINE, (CommandProcessor::fifo.PEToken == (userdata&0xFFFF)), "WTF? BPMEM_PE_TOKEN_INT_ID's token != BPMEM_PE_TOKEN_ID's token" ); + LOGV(PIXELENGINE, 1, "VIDEO Plugin raises INT_CAUSE_PE_TOKEN (btw, token: %04x)", CommandProcessor::fifo.PEToken); + UpdateInterrupts(); + //} + //else + // LOGV(PIXELENGINE, 1, "VIDEO Plugin wrote token: %i", CommandProcessor::fifo.PEToken); } void SetFinish_OnMainThread(u64 userdata, int cyclesLate) @@ -183,8 +188,23 @@ void SetFinish_OnMainThread(u64 userdata, int cyclesLate) // THIS IS EXECUTED FROM VIDEO THREAD void SetToken(const u16 _token, const int _bSetTokenAcknowledge) { - CoreTiming::ScheduleEvent_Threadsafe( - 0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16)); + // TODO?: set-token-value and set-token-INT could be merged since set-token-INT own the token value. + if (_bSetTokenAcknowledge) // set token INT + { + CommandProcessor::IncrementGPWDToken(); // for DC watchdog hack since PEToken seems to be a frame-finish too + CoreTiming::ScheduleEvent_Threadsafe( + 0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16)); + } + else // set token value + { + // we do it directly from videoThread because of + // Super Monkey Ball Advance +#ifdef _WIN32 + InterlockedExchange((LONG*)&CommandProcessor::fifo.PEToken, _token); +#else + Common::InterlockedExchange((int*)&CommandProcessor::fifo.PEToken, _token); +#endif + } } // SetFinish diff --git a/Source/PluginSpecs/pluginspecs_video.h b/Source/PluginSpecs/pluginspecs_video.h index 74c7f51f57..b3ccc0d3ae 100644 --- a/Source/PluginSpecs/pluginspecs_video.h +++ b/Source/PluginSpecs/pluginspecs_video.h @@ -35,13 +35,17 @@ typedef struct volatile u32 CPReadPointer; volatile u32 CPBreakpoint; + // Super Monkey Ball Adventure require this. + // Because the read&check-PEToken-loop stays in its JITed block I suppose. + // So no possiblity to ack the Token irq by the scheduler until some sort of PPC watchdog do its mess. + volatile u16 PEToken; + volatile BOOL bFF_GPReadEnable; volatile BOOL bFF_BPEnable; volatile BOOL bFF_GPLinkEnable; volatile BOOL bFF_Breakpoint; // for GP watchdog hack - volatile BOOL Fake_GPWDInterrupt; volatile u32 Fake_GPWDToken; // cicular incrementer } SCPFifoStruct;