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:
parent
ba7f7cd8b7
commit
337ff1f56b
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue