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
|
// - 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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue