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
This commit is contained in:
memberTwo.mb2 2008-11-20 12:16:51 +00:00
parent ba7f7cd8b7
commit 337ff1f56b
3 changed files with 58 additions and 27 deletions

View File

@ -25,6 +25,10 @@
// - ZTP: seems to use PEfinish only // - ZTP: seems to use PEfinish only
// - Animal Crossing: PEfinish at start but there's a bug... // - Animal Crossing: PEfinish at start but there's a bug...
// There's tons of HiWmk/LoWmk ping pong -> Another sync fashion? // 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): // *What I guess (thx to asynchronous DualCore mode):
// PPC have a frame-finish watchdog. Handled by system timming stuff like the decrementer. // PPC have a frame-finish watchdog. Handled by system timming stuff like the decrementer.
@ -144,6 +148,7 @@ int m_bboxbottom;
u16 m_tokenReg; u16 m_tokenReg;
SCPFifoStruct fifo; //This one is shared between gfx thread and emulator thread SCPFifoStruct fifo; //This one is shared between gfx thread and emulator thread
static u32 fake_GPWatchdogLastToken = 0;
void DoState(PointerWrap &p) void DoState(PointerWrap &p)
{ {
@ -181,15 +186,10 @@ void IncrementGPWDToken()
// Check every FAKE_GP_WATCHDOG_PERIOD if a PE-frame-finish occured // Check every FAKE_GP_WATCHDOG_PERIOD if a PE-frame-finish occured
// if not then lock CPUThread until GP finish a frame. // if not then lock CPUThread until GP finish a frame.
u32 fake_GPWatchdogLastToken = 0;
void WaitForFrameFinish() 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; fake_GPWatchdogLastToken = fifo.Fake_GPWDToken;
} }
@ -217,9 +217,10 @@ void Init()
fifo.bFF_GPReadEnable = FALSE; fifo.bFF_GPReadEnable = FALSE;
fifo.bFF_GPLinkEnable = FALSE; fifo.bFF_GPLinkEnable = FALSE;
fifo.bFF_BPEnable = FALSE; fifo.bFF_BPEnable = FALSE;
fifo.PEToken = 0;
// for GP watchdog hack // for GP watchdog hack
fifo.Fake_GPWDInterrupt = FALSE;
fifo.Fake_GPWDToken = 0; fifo.Fake_GPWDToken = 0;
fake_GPWatchdogLastToken = 0;
et_UpdateInterrupts = CoreTiming::RegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper); et_UpdateInterrupts = CoreTiming::RegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper);
} }
@ -376,7 +377,7 @@ void Write16(const u16 _Value, const u32 _Address)
// update interrupts // update interrupts
UpdateInterrupts(); UpdateInterrupts();
LOG(COMMANDPROCESSOR,"write to STATUS_REGISTER : %04x", _Value); LOG(COMMANDPROCESSOR,"\t write to STATUS_REGISTER : %04x", _Value);
} }
break; break;
@ -413,14 +414,16 @@ void Write16(const u16 _Value, const u32 _Address)
} }
}/**/ }/**/
UpdateInterrupts(); 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_GPReadEnable ? "ON" : "OFF"
, fifo.bFF_GPLinkEnable ? "ON" : "OFF" , fifo.bFF_GPLinkEnable ? "ON" : "OFF"
, fifo.bFF_BPEnable ? "ON" : "OFF" , fifo.bFF_BPEnable ? "ON" : "OFF"
, m_CPCtrlReg.CPIntEnable ? "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; break;
@ -429,12 +432,15 @@ void Write16(const u16 _Value, const u32 _Address)
UCPClearReg tmpClearReg(_Value); UCPClearReg tmpClearReg(_Value);
m_CPClearReg.Hex = 0; m_CPClearReg.Hex = 0;
LOG(COMMANDPROCESSOR,"write to CLEAR_REGISTER : %04x",_Value); LOG(COMMANDPROCESSOR,"\t write to CLEAR_REGISTER : %04x",_Value);
} }
break; break;
// Fifo Registers // 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_LO: WriteLow ((u32 &)fifo.CPBase, _Value); fifo.CPBase &= 0xFFFFFFE0; break;
case FIFO_BASE_HI: WriteHigh((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 // - CPU can write to fifo
// - disable Underflow interrupt // - disable Underflow interrupt
LOG(COMMANDPROCESSOR, "(GatherPipeBursted): CPHiWatermark reached");
// Wait for GPU to catch up // Wait for GPU to catch up
//while (!(fifo.bFF_BPEnable && fifo.bFF_Breakpoint) && fifo.CPReadWriteDistance > (s32)fifo.CPLoWatermark) //while (!(fifo.bFF_BPEnable && fifo.bFF_Breakpoint) && fifo.CPReadWriteDistance > (s32)fifo.CPLoWatermark)
while (fifo.CPReadWriteDistance > fifo.CPLoWatermark) while (fifo.CPReadWriteDistance > fifo.CPLoWatermark)

View File

@ -55,7 +55,6 @@ union UPECtrlReg
// STATE_TO_SAVE // STATE_TO_SAVE
static UPECtrlReg g_ctrlReg; static UPECtrlReg g_ctrlReg;
static u16 g_token = 0;
static bool g_bSignalTokenInterrupt; static bool g_bSignalTokenInterrupt;
static bool g_bSignalFinishInterrupt; static bool g_bSignalFinishInterrupt;
@ -66,7 +65,7 @@ int et_SetFinishOnMainThread;
void DoState(PointerWrap &p) void DoState(PointerWrap &p)
{ {
p.Do(g_ctrlReg); p.Do(g_ctrlReg);
p.Do(g_token); p.Do(CommandProcessor::fifo.PEToken);
p.Do(g_bSignalTokenInterrupt); p.Do(g_bSignalTokenInterrupt);
p.Do(g_bSignalFinishInterrupt); p.Do(g_bSignalFinishInterrupt);
} }
@ -78,7 +77,6 @@ void SetFinish_OnMainThread(u64 userdata, int cyclesLate);
void Init() void Init()
{ {
g_token = 0;
g_ctrlReg.Hex = 0; g_ctrlReg.Hex = 0;
et_SetTokenOnMainThread = CoreTiming::RegisterEvent("SetToken", SetToken_OnMainThread); et_SetTokenOnMainThread = CoreTiming::RegisterEvent("SetToken", SetToken_OnMainThread);
@ -93,10 +91,12 @@ void Read16(u16& _uReturnValue, const u32 _iAddress)
{ {
case CTRL_REGISTER: case CTRL_REGISTER:
_uReturnValue = g_ctrlReg.Hex; _uReturnValue = g_ctrlReg.Hex;
LOG(PIXELENGINE,"\t CTRL_REGISTER : %04x", _uReturnValue);
return; return;
case TOKEN_REG: case TOKEN_REG:
_uReturnValue = g_token; _uReturnValue = CommandProcessor::fifo.PEToken;
LOG(PIXELENGINE,"\t TOKEN_REG : %04x", _uReturnValue);
return; return;
default: default:
@ -135,9 +135,10 @@ void Write16(const u16 _iValue, const u32 _iAddress)
break; break;
case TOKEN_REG: 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 //only the gx pipeline is supposed to be able to write here
g_token = _iValue; //g_token = _iValue;
break; break;
} }
} }
@ -162,15 +163,19 @@ void UpdateInterrupts()
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_PE_FINISH, false); 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) void SetToken_OnMainThread(u64 userdata, int cyclesLate)
{ {
// In the future: schedule callback that does the rest of this function //if (userdata >> 16)
// This way we will be threadsafe //{
if (userdata >> 16)
g_bSignalTokenInterrupt = true; g_bSignalTokenInterrupt = true;
g_token = (u16)(userdata & 0xFFFF); _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 wrote token: %i", g_token); LOGV(PIXELENGINE, 1, "VIDEO Plugin raises INT_CAUSE_PE_TOKEN (btw, token: %04x)", CommandProcessor::fifo.PEToken);
UpdateInterrupts(); UpdateInterrupts();
//}
//else
// LOGV(PIXELENGINE, 1, "VIDEO Plugin wrote token: %i", CommandProcessor::fifo.PEToken);
} }
void SetFinish_OnMainThread(u64 userdata, int cyclesLate) void SetFinish_OnMainThread(u64 userdata, int cyclesLate)
@ -183,8 +188,23 @@ void SetFinish_OnMainThread(u64 userdata, int cyclesLate)
// THIS IS EXECUTED FROM VIDEO THREAD // THIS IS EXECUTED FROM VIDEO THREAD
void SetToken(const u16 _token, const int _bSetTokenAcknowledge) void SetToken(const u16 _token, const int _bSetTokenAcknowledge)
{ {
CoreTiming::ScheduleEvent_Threadsafe( // TODO?: set-token-value and set-token-INT could be merged since set-token-INT own the token value.
0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16)); 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 // SetFinish

View File

@ -35,13 +35,17 @@ typedef struct
volatile u32 CPReadPointer; volatile u32 CPReadPointer;
volatile u32 CPBreakpoint; 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_GPReadEnable;
volatile BOOL bFF_BPEnable; volatile BOOL bFF_BPEnable;
volatile BOOL bFF_GPLinkEnable; volatile BOOL bFF_GPLinkEnable;
volatile BOOL bFF_Breakpoint; volatile BOOL bFF_Breakpoint;
// for GP watchdog hack // for GP watchdog hack
volatile BOOL Fake_GPWDInterrupt;
volatile u32 Fake_GPWDToken; // cicular incrementer volatile u32 Fake_GPWDToken; // cicular incrementer
} SCPFifoStruct; } SCPFifoStruct;