mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-24 22:59:47 -06:00
A bit more proper GP fifo emulation: some DC fixes, some hacks too, more comments and TODOs.
TODO: the linux part. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1017 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
@ -16,6 +16,37 @@
|
|||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
|
|
||||||
|
// NOTES (mb2):
|
||||||
|
|
||||||
|
// * GP/CPU sync can be done by several way:
|
||||||
|
// - MP1 use BP (breakpoint) in movie-menus and mostly PEtoken in 3D
|
||||||
|
// - ZWW as Crazy Taxi: PEfinish (GXSetDrawDone)
|
||||||
|
// - SMS: BP, PEToken, PEfinish
|
||||||
|
// - 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?
|
||||||
|
|
||||||
|
// * BPs are needed for some game GP/CPU sync.
|
||||||
|
// But it could slowdown (MP1 at least) because our GP in DC is faster than "expected" in some area.
|
||||||
|
// eg: in movie-menus in MP1, BP are reached quickly.
|
||||||
|
// The bad thing is that involve too much PPC work (int ack, lock GP, reset BP, new BP addr, unlock BP...) hence the slowdown.
|
||||||
|
// Anyway, emulation is more accurate like this and it emulate some sort of better load balancing.
|
||||||
|
// Eather way in those area a more accurate GP timing could be done by slowing down the GP or something less stupid.
|
||||||
|
|
||||||
|
// * funny, in revs before those with this note, BP irq wasn't cleared (a bug indeed) and MP1 menus was faster.
|
||||||
|
// BP irq was raised and ack just once but never cleared. However it's sufficient for MP1 to work.
|
||||||
|
// I see a possible ugly hack there :p
|
||||||
|
|
||||||
|
// TODO (mb2):
|
||||||
|
// * raise watermark Ov/Un irq: DONE but not commited because useless(?) and it slowdown DC.
|
||||||
|
// TODO: commit #ifdef'ed?... if I'm begged :p
|
||||||
|
// * raise ReadIdle/CmdIdle irq and observe behaviour of MP1 & ZTP (at least)
|
||||||
|
// * find who command a complete fifo flush (could be some sort of timeout + wait for ReadIdle irq)
|
||||||
|
// * investigate VI and PI for fixing the DC ZTP bug.
|
||||||
|
// * Clean useless comments and debug stuff in Read16, Write16, GatherPipeBursted when sync will be fixed for DC
|
||||||
|
// * (reminder) do the same in:
|
||||||
|
// PeripheralInterface.cpp, PixelEngine.cpp, OGL->BPStructs.cpp, fifo.cpp... ok just check change log >>
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// * Kick GPU from dispatcher, not from writes
|
// * Kick GPU from dispatcher, not from writes
|
||||||
// * Thunking framework
|
// * Thunking framework
|
||||||
@ -149,9 +180,9 @@ void Init()
|
|||||||
|
|
||||||
m_tokenReg = 0;
|
m_tokenReg = 0;
|
||||||
|
|
||||||
fifo.bFF_GPReadEnable = false;
|
fifo.bFF_GPReadEnable = FALSE;
|
||||||
fifo.bFF_GPLinkEnable = false;
|
fifo.bFF_GPLinkEnable = FALSE;
|
||||||
fifo.bFF_BPEnable = false;
|
fifo.bFF_BPEnable = FALSE;
|
||||||
|
|
||||||
et_UpdateInterrupts = CoreTiming::RegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper);
|
et_UpdateInterrupts = CoreTiming::RegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper);
|
||||||
|
|
||||||
@ -172,21 +203,6 @@ void Shutdown()
|
|||||||
void Read16(u16& _rReturnValue, const u32 _Address)
|
void Read16(u16& _rReturnValue, const u32 _Address)
|
||||||
{
|
{
|
||||||
LOG(COMMANDPROCESSOR, "(r): 0x%08x", _Address);
|
LOG(COMMANDPROCESSOR, "(r): 0x%08x", _Address);
|
||||||
if (Core::g_CoreStartupParameter.bUseDualCore)
|
|
||||||
{
|
|
||||||
//if ((_Address&0xFFF)>=0x20)
|
|
||||||
{
|
|
||||||
// Wait for GPU to catch up
|
|
||||||
// TODO (mb2) fix the H/LWM thing with CPReadWriteDistance
|
|
||||||
// instead of stupidly waiting for a complete fifo flush
|
|
||||||
u32 ct=0;
|
|
||||||
while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance > 0 && !(fifo.bFF_BPEnable && fifo.bFF_Breakpoint))
|
|
||||||
//while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance > fifo.CPHiWatermark && !(fifo.bFF_BPEnable && fifo.bFF_Breakpoint))
|
|
||||||
ct++;
|
|
||||||
if (ct) {LOG(COMMANDPROCESSOR, "(Read16): %lu cycle for nothing :[ ", ct);}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
switch (_Address & 0xFFF)
|
switch (_Address & 0xFFF)
|
||||||
{
|
{
|
||||||
case STATUS_REGISTER: _rReturnValue = m_CPStatusReg.Hex; return;
|
case STATUS_REGISTER: _rReturnValue = m_CPStatusReg.Hex; return;
|
||||||
@ -265,15 +281,35 @@ void Write16(const u16 _Value, const u32 _Address)
|
|||||||
|
|
||||||
if (Core::g_CoreStartupParameter.bUseDualCore)
|
if (Core::g_CoreStartupParameter.bUseDualCore)
|
||||||
{
|
{
|
||||||
|
// Force complete fifo flush if we attempt to set/reset the fifo (API GXSetGPFifo or equivalent)
|
||||||
|
// It's kind of an API hack but it works for lots of games... and I hope it's the same way for every games.
|
||||||
|
// TODO: HLE for GX fifo's APIs?
|
||||||
|
// Here is the hack:
|
||||||
|
// - if (attempt to overwrite CTRL_REGISTER by 0x0000)
|
||||||
|
// // then we assume CPReadWriteDistance will be reset to 0x00000000 very soon.
|
||||||
|
// - if (fifo is not empty)
|
||||||
|
// // (not 100% sure): shouln't happens unless PPC think having trouble with the sync
|
||||||
|
// // and it attempt a fifo recovery (look for PI_FIFO_RESET in log).
|
||||||
|
// // If we want to emulate self fifo recovery we need proper GX metrics emulation... yeah sure :p
|
||||||
|
// - spin until fifo is empty
|
||||||
|
// - else
|
||||||
|
// - normal write16
|
||||||
|
|
||||||
//if ((_Address&0xFFF) >= 0x20) // <- FIXME (mb2) it was a good idea
|
if (((_Address&0xFFF) == CTRL_REGISTER) && (_Value == 0)) // API hack
|
||||||
{
|
{
|
||||||
// Wait for GPU to catch up
|
// weird MP1 redo that right after linking fifo with GP... hmmm
|
||||||
// TODO (mb2) fix the H/LWM thing with CPReadWriteDistance
|
// maybe waiting for an irq like ReadIdle... dunno
|
||||||
// instead of stupidly waiting for complete fifo flush
|
/*_dbg_assert_msg_(COMMANDPROCESSOR, fifo.CPReadWriteDistance == 0,
|
||||||
|
"WTF! Something went wrong with GP/PPC the sync! -> CPReadWriteDistance: 0x%08X\n"
|
||||||
|
" - The fifo is not empty but we are going to lock it anyway.\n"
|
||||||
|
" - \"Normaly\", this is due to fifo-hang-so-lets-attempt-recovery.\n"
|
||||||
|
" - The bad news is dolphin don't support special recovery features like GXfifo's metric yet.\n"
|
||||||
|
" - The good news is, the time you read that message, the fifo should be empty now :p\n"
|
||||||
|
" - Anyway, fifo flush will be forced if you press OK and dolphin might continue to work...\n"
|
||||||
|
" - We aren't betting on that :)", fifo.CPReadWriteDistance);
|
||||||
|
/**/
|
||||||
u32 ct=0;
|
u32 ct=0;
|
||||||
while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance > 0 && !(fifo.bFF_BPEnable && fifo.bFF_Breakpoint))
|
while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance > 0 )
|
||||||
//while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance > fifo.CPHiWatermark && !(fifo.bFF_BPEnable && fifo.bFF_Breakpoint))
|
|
||||||
ct++;
|
ct++;
|
||||||
if (ct) {LOG(COMMANDPROCESSOR, "(Write16): %lu cycles for nothing :[ ", ct);}
|
if (ct) {LOG(COMMANDPROCESSOR, "(Write16): %lu cycles for nothing :[ ", ct);}
|
||||||
}
|
}
|
||||||
@ -296,14 +332,17 @@ void Write16(const u16 _Value, const u32 _Address)
|
|||||||
m_CPStatusReg.ReadIdle = 1;
|
m_CPStatusReg.ReadIdle = 1;
|
||||||
m_CPStatusReg.CommandIdle = 1;
|
m_CPStatusReg.CommandIdle = 1;
|
||||||
|
|
||||||
|
// TOCHECK (mb2): could BP irq be cleared here too?
|
||||||
|
//if (tmpStatus.Breakpoint!=m_CPStatusReg.Breakpoint) _asm int 3
|
||||||
// breakpoint
|
// breakpoint
|
||||||
if (tmpStatus.Breakpoint)
|
/*if (tmpStatus.Breakpoint)
|
||||||
{
|
{
|
||||||
m_CPStatusReg.Breakpoint = 0;
|
m_CPStatusReg.Breakpoint = 0;
|
||||||
}
|
}
|
||||||
//fifo.bFF_Breakpoint = m_CPStatusReg.Breakpoint;
|
//fifo.bFF_Breakpoint = m_CPStatusReg.Breakpoint;
|
||||||
fifo.bFF_Breakpoint = m_CPStatusReg.Breakpoint ? true : false;
|
fifo.bFF_Breakpoint = m_CPStatusReg.Breakpoint ? true : false;
|
||||||
//LOG(COMMANDPROCESSOR,"fifo.bFF_Breakpoint : %i",fifo.bFF_Breakpoint);
|
//LOG(COMMANDPROCESSOR,"fifo.bFF_Breakpoint : %i",fifo.bFF_Breakpoint);
|
||||||
|
/**/
|
||||||
|
|
||||||
// update interrupts
|
// update interrupts
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
@ -316,12 +355,43 @@ void Write16(const u16 _Value, const u32 _Address)
|
|||||||
{
|
{
|
||||||
m_CPCtrlReg.Hex = _Value;
|
m_CPCtrlReg.Hex = _Value;
|
||||||
|
|
||||||
fifo.bFF_GPReadEnable = m_CPCtrlReg.GPReadEnable ? true : false;
|
#ifdef _WIN32
|
||||||
fifo.bFF_GPLinkEnable = m_CPCtrlReg.GPLinkEnable ? true : false;
|
InterlockedExchange((LONG*)&fifo.bFF_GPReadEnable, m_CPCtrlReg.GPReadEnable);
|
||||||
fifo.bFF_BPEnable = m_CPCtrlReg.BPEnable ? true : false;
|
InterlockedExchange((LONG*)&fifo.bFF_GPLinkEnable, m_CPCtrlReg.GPLinkEnable);
|
||||||
//LOG(COMMANDPROCESSOR,"bFF_GPReadEnable: %i bFF_GPLinkEnable: %i bFF_BPEnable: %i", fifo.bFF_GPReadEnable, fifo.bFF_GPLinkEnable, fifo.bFF_BPEnable);
|
InterlockedExchange((LONG*)&fifo.bFF_BPEnable, m_CPCtrlReg.BPEnable);
|
||||||
|
#else
|
||||||
|
#warning "Hi pingouin lover :p. Just make sure the following is ok for linux please."
|
||||||
|
// TODO: safely?
|
||||||
|
fifo.bFF_GPReadEnable = m_CPCtrlReg.GPReadEnable;
|
||||||
|
fifo.bFF_GPLinkEnable = m_CPCtrlReg.GPLinkEnable;
|
||||||
|
fifo.bFF_BPEnable = m_CPCtrlReg.BPEnable;
|
||||||
|
#endif
|
||||||
|
// TOCHECK (mb2): could BP irq be cleared with w16 to STATUS_REGISTER?
|
||||||
|
// funny hack: eg in MP1 if we disable the clear breakpoint ability by commenting this block
|
||||||
|
// the game is of course faster but looks stable too.
|
||||||
|
// Well, the hack is more stable than the "proper" way actualy :p ... it breaks MP2 when ship lands
|
||||||
|
// So I let the hack for now.
|
||||||
|
// TODO (mb2): fix this!
|
||||||
|
|
||||||
|
// BP interrupt is cleared here
|
||||||
|
/*if (m_CPCtrlReg.CPIntEnable)
|
||||||
|
{
|
||||||
|
LOG(COMMANDPROCESSOR,"\t ClearBreakpoint interrupt");
|
||||||
|
// yes an SC hack, single core mode isn't very gc spec compliant :D
|
||||||
|
// TODO / FIXME : fix SC BPs. Only because it's pretty ugly to have a if{} here just for that.
|
||||||
|
if (Core::g_CoreStartupParameter.bUseDualCore)
|
||||||
|
{
|
||||||
|
m_CPStatusReg.Breakpoint = 0;
|
||||||
|
InterlockedExchange((LONG*)&fifo.bFF_Breakpoint, 0);
|
||||||
|
}
|
||||||
|
}/**/
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
|
LOG(COMMANDPROCESSOR, "\t GPREAD %s | CPULINK %s | BP %s || CPIntEnable %s"
|
||||||
|
, fifo.bFF_GPReadEnable ? "ON" : "OFF"
|
||||||
|
, fifo.bFF_GPLinkEnable ? "ON" : "OFF"
|
||||||
|
, fifo.bFF_BPEnable ? "ON" : "OFF"
|
||||||
|
, m_CPCtrlReg.CPIntEnable ? "ON" : "OFF"
|
||||||
|
);
|
||||||
|
|
||||||
LOG(COMMANDPROCESSOR,"write to CTRL_REGISTER : %04x", _Value);
|
LOG(COMMANDPROCESSOR,"write to CTRL_REGISTER : %04x", _Value);
|
||||||
}
|
}
|
||||||
@ -345,6 +415,8 @@ void Write16(const u16 _Value, const u32 _Address)
|
|||||||
case FIFO_END_HI: WriteHigh((u32 &)fifo.CPEnd, _Value); fifo.CPEnd &= 0xFFFFFFE0; break;
|
case FIFO_END_HI: WriteHigh((u32 &)fifo.CPEnd, _Value); fifo.CPEnd &= 0xFFFFFFE0; break;
|
||||||
|
|
||||||
// Hm. Should we really & these with FFFFFFE0?
|
// Hm. Should we really & these with FFFFFFE0?
|
||||||
|
// (mb2): never seen 32B not aligned values for those following regs.
|
||||||
|
// fifo.CPEnd is the only value that could be not 32B aligned so far.
|
||||||
case FIFO_WRITE_POINTER_LO:
|
case FIFO_WRITE_POINTER_LO:
|
||||||
WriteLow ((u32 &)fifo.CPWritePointer, _Value); fifo.CPWritePointer &= 0xFFFFFFE0;
|
WriteLow ((u32 &)fifo.CPWritePointer, _Value); fifo.CPWritePointer &= 0xFFFFFFE0;
|
||||||
//LOG(COMMANDPROCESSOR,"write to FIFO_WRITE_POINTER_LO : %04x", _Value);
|
//LOG(COMMANDPROCESSOR,"write to FIFO_WRITE_POINTER_LO : %04x", _Value);
|
||||||
@ -369,23 +441,24 @@ void Write16(const u16 _Value, const u32 _Address)
|
|||||||
|
|
||||||
case FIFO_BP_LO:
|
case FIFO_BP_LO:
|
||||||
WriteLow ((u32 &)fifo.CPBreakpoint, _Value);
|
WriteLow ((u32 &)fifo.CPBreakpoint, _Value);
|
||||||
//LOG(COMMANDPROCESSOR,"write to FIFO_BP_LO : %04x", _Value);
|
LOG(COMMANDPROCESSOR,"write to FIFO_BP_LO : %04x", _Value);
|
||||||
break;
|
break;
|
||||||
case FIFO_BP_HI:
|
case FIFO_BP_HI:
|
||||||
WriteHigh((u32 &)fifo.CPBreakpoint, _Value);
|
WriteHigh((u32 &)fifo.CPBreakpoint, _Value);
|
||||||
//LOG(COMMANDPROCESSOR,"write to FIFO_BP_LO : %04x", _Value);
|
LOG(COMMANDPROCESSOR,"write to FIFO_BP_HI : %04x", _Value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// ignored writes
|
// ignored writes
|
||||||
case FIFO_RW_DISTANCE_HI:
|
case FIFO_RW_DISTANCE_HI:
|
||||||
case FIFO_RW_DISTANCE_LO:
|
case FIFO_RW_DISTANCE_LO:
|
||||||
//LOG(COMMANDPROCESSOR,"try to write to %s : %04x",(_Address & FIFO_RW_DISTANCE_HI) ? "FIFO_RW_DISTANCE_HI" : "FIFO_RW_DISTANCE_LO", _Value);
|
LOG(COMMANDPROCESSOR,"try to write to %s : %04x",((_Address & 0xFFF) == FIFO_RW_DISTANCE_HI) ? "FIFO_RW_DISTANCE_HI" : "FIFO_RW_DISTANCE_LO", _Value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// (mb2) very dangerous to UpdateFifoRegister() that way in DC when there no criticalsections anymore
|
||||||
|
// ... completely useless btw :p
|
||||||
// update the registers and run the fifo
|
// update the registers and run the fifo
|
||||||
// This will recursively enter fifo.sync, TODO(ector): is this good?
|
//UpdateFifoRegister();
|
||||||
UpdateFifoRegister();
|
|
||||||
//if (Core::g_CoreStartupParameter.bUseDualCore)
|
//if (Core::g_CoreStartupParameter.bUseDualCore)
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
//LeaveCriticalSection(&fifo.sync);
|
//LeaveCriticalSection(&fifo.sync);
|
||||||
@ -417,34 +490,66 @@ void GatherPipeBursted()
|
|||||||
fifo.CPWritePointer += GPFifo::GATHER_PIPE_SIZE;
|
fifo.CPWritePointer += GPFifo::GATHER_PIPE_SIZE;
|
||||||
if (fifo.CPWritePointer >= fifo.CPEnd)
|
if (fifo.CPWritePointer >= fifo.CPEnd)
|
||||||
fifo.CPWritePointer = fifo.CPBase;
|
fifo.CPWritePointer = fifo.CPBase;
|
||||||
|
|
||||||
// Wait for GPU to catch up
|
|
||||||
// TODO (mb2) fix the H/LWM thing with CPReadWriteDistance
|
|
||||||
// instead of stupidly waiting for a complete fifo flush
|
|
||||||
u32 ct=0;
|
|
||||||
//while (!(fifo.bFF_BPEnable && fifo.bFF_Breakpoint) && fifo.CPReadWriteDistance > 0)
|
|
||||||
while (!(fifo.bFF_BPEnable && fifo.bFF_Breakpoint) && fifo.CPReadWriteDistance > (s32)fifo.CPHiWatermark)
|
|
||||||
//Common::SleepCurrentThread(1000); // 1s for test. We shouldn't fall here ever
|
|
||||||
ct++;
|
|
||||||
if (ct) {LOG(COMMANDPROCESSOR, "(GatherPipeBursted): %lu cycle for nothing :[ ", ct);}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
InterlockedExchangeAdd((LONG*)&fifo.CPReadWriteDistance, GPFifo::GATHER_PIPE_SIZE);
|
InterlockedExchangeAdd((LONG*)&fifo.CPReadWriteDistance, GPFifo::GATHER_PIPE_SIZE);
|
||||||
#else
|
#else
|
||||||
Common::InterlockedExchangeAdd((int*)&fifo.CPReadWriteDistance, GPFifo::GATHER_PIPE_SIZE);
|
Common::InterlockedExchangeAdd((int*)&fifo.CPReadWriteDistance, GPFifo::GATHER_PIPE_SIZE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Wait for GPU to catch up
|
||||||
|
#if 0
|
||||||
|
// High watermark overflow handling: hacked way
|
||||||
|
u32 ct=0;
|
||||||
|
while (!(fifo.bFF_BPEnable && fifo.bFF_Breakpoint) && fifo.CPReadWriteDistance > (s32)fifo.CPHiWatermark)
|
||||||
|
{
|
||||||
|
ct++;
|
||||||
|
// dunno if others threads (like the audio thread) really need a forced context switch here
|
||||||
|
//Common::SleepCurrentThread(1);
|
||||||
|
}
|
||||||
|
if (ct) {LOG(COMMANDPROCESSOR, "(GatherPipeBursted): %lu cycles for nothing :[ ", ct);}
|
||||||
|
#else
|
||||||
|
// High watermark overflow handling: less hacked way
|
||||||
|
u32 ct=0;
|
||||||
|
if (fifo.CPReadWriteDistance > (s32)fifo.CPHiWatermark)
|
||||||
|
{
|
||||||
|
// we should raise an Ov interrupt for an accurate fifo emulation and let PPC deal with it.
|
||||||
|
// But it slowdown things because of if(interrupt blah blah){} blocks for each 32B fifo transactions.
|
||||||
|
// CPU would be a bit more loaded too by interrupt handling...
|
||||||
|
// Eather way, CPU would have the ability to resume another thread.
|
||||||
|
// To be clear: this spin loop is like a critical section spin loop in the emulated GX thread hence "hacked way"
|
||||||
|
|
||||||
|
// Yes, in real life, the only purpose of the low watermark interrupt is just for cooling down OV contention.
|
||||||
|
// - @ game start -> watermark init: Overflow enabled, Underflow disabled
|
||||||
|
// - if (OV is raised)
|
||||||
|
// - CPU stop to write to fifo
|
||||||
|
// - enable Underflow interrupt (this only happens if OV is raised)
|
||||||
|
// - do other things
|
||||||
|
// - if (Underflow is raised (implicite: AND if an OV has been raised))
|
||||||
|
// - CPU can write to fifo
|
||||||
|
// - disable Underflow interrupt
|
||||||
|
|
||||||
|
//while (!(fifo.bFF_BPEnable && fifo.bFF_Breakpoint) && fifo.CPReadWriteDistance > (s32)fifo.CPLoWatermark)
|
||||||
|
while (fifo.CPReadWriteDistance > (s32)fifo.CPLoWatermark)
|
||||||
|
{
|
||||||
|
ct++;
|
||||||
|
// dunno if others threads (like the audio thread) really need a forced context switch here
|
||||||
|
//Common::SleepCurrentThread(1);
|
||||||
|
}
|
||||||
|
if (ct) {LOG(COMMANDPROCESSOR, "(GatherPipeBursted): %lu cycles for nothing :[ ", ct);}
|
||||||
|
/**/
|
||||||
|
}
|
||||||
|
#endif
|
||||||
// check if we are in sync
|
// check if we are in sync
|
||||||
_assert_msg_(COMMANDPROCESSOR, fifo.CPWritePointer == CPeripheralInterface::Fifo_CPUWritePointer, "FIFOs linked but out of sync");
|
_assert_msg_(COMMANDPROCESSOR, fifo.CPWritePointer == CPeripheralInterface::Fifo_CPUWritePointer, "FIFOs linked but out of sync");
|
||||||
_assert_msg_(COMMANDPROCESSOR, fifo.CPBase == CPeripheralInterface::Fifo_CPUBase, "FIFOs linked but out of sync");
|
_assert_msg_(COMMANDPROCESSOR, fifo.CPBase == CPeripheralInterface::Fifo_CPUBase, "FIFOs linked but out of sync");
|
||||||
_assert_msg_(COMMANDPROCESSOR, fifo.CPEnd == CPeripheralInterface::Fifo_CPUEnd, "FIFOs linked but out of sync");
|
_assert_msg_(COMMANDPROCESSOR, fifo.CPEnd == CPeripheralInterface::Fifo_CPUEnd, "FIFOs linked but out of sync");
|
||||||
|
|
||||||
if (fifo.bFF_Breakpoint)
|
// no not from CPU. Only GP can throw BP irq
|
||||||
|
/*if (fifo.bFF_Breakpoint)
|
||||||
{
|
{
|
||||||
m_CPStatusReg.Breakpoint = 1;
|
m_CPStatusReg.Breakpoint = 1;
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
}
|
}/**/
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -476,9 +581,9 @@ void CatchUpGPU()
|
|||||||
if ((fifo.CPReadPointer & ~0x1F) == (fifo.CPBreakpoint & ~0x1F))
|
if ((fifo.CPReadPointer & ~0x1F) == (fifo.CPBreakpoint & ~0x1F))
|
||||||
{
|
{
|
||||||
//_assert_msg_(GEKKO,0,"BP: %08x",fifo.CPBreakpoint);
|
//_assert_msg_(GEKKO,0,"BP: %08x",fifo.CPBreakpoint);
|
||||||
|
//LOG(COMMANDPROCESSOR,"!!! BP irq raised");
|
||||||
fifo.bFF_Breakpoint = 1;
|
fifo.bFF_Breakpoint = 1;
|
||||||
m_CPStatusReg.Breakpoint = 1;
|
m_CPStatusReg.Breakpoint = 1;
|
||||||
//g_VideoInitialize.pUpdateInterrupts();
|
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -508,6 +613,7 @@ void CatchUpGPU()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
// __________________________________________________________________________________________________
|
||||||
|
// !!! only called on single core mode now
|
||||||
// UpdateFifoRegister
|
// UpdateFifoRegister
|
||||||
// It's no problem if the gfx falls behind a little bit. Better make sure to stop the cpu thread
|
// It's no problem if the gfx falls behind a little bit. Better make sure to stop the cpu thread
|
||||||
// when the distance is way huge, though.
|
// when the distance is way huge, though.
|
||||||
@ -523,10 +629,6 @@ void CatchUpGPU()
|
|||||||
void UpdateFifoRegister()
|
void UpdateFifoRegister()
|
||||||
{
|
{
|
||||||
// update the distance
|
// update the distance
|
||||||
//#ifdef _WIN32
|
|
||||||
// not needed since we are already in the critical section in DC mode -> see write16(...) (unique reference)
|
|
||||||
// if (Core::g_CoreStartupParameter.bUseDualCore) EnterCriticalSection(&fifo.sync);
|
|
||||||
//#endif
|
|
||||||
int wp = fifo.CPWritePointer;
|
int wp = fifo.CPWritePointer;
|
||||||
int rp = fifo.CPReadPointer;
|
int rp = fifo.CPReadPointer;
|
||||||
int dist;
|
int dist;
|
||||||
@ -534,16 +636,8 @@ void UpdateFifoRegister()
|
|||||||
dist = wp - rp;
|
dist = wp - rp;
|
||||||
else
|
else
|
||||||
dist = (wp - fifo.CPBase) + (fifo.CPEnd - rp);
|
dist = (wp - fifo.CPBase) + (fifo.CPEnd - rp);
|
||||||
#ifdef _WIN32
|
|
||||||
InterlockedExchange((LONG*)&fifo.CPReadWriteDistance, dist);
|
|
||||||
#else
|
|
||||||
fifo.CPReadWriteDistance = dist;
|
fifo.CPReadWriteDistance = dist;
|
||||||
#endif
|
CatchUpGPU();
|
||||||
//#ifdef _WIN32
|
|
||||||
// not needed since we are already in the critical section in DC mode (see write16)
|
|
||||||
// if (Core::g_CoreStartupParameter.bUseDualCore) LeaveCriticalSection(&fifo.sync);
|
|
||||||
//#endif
|
|
||||||
if (!Core::g_CoreStartupParameter.bUseDualCore) CatchUpGPU();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateInterrupts()
|
void UpdateInterrupts()
|
||||||
|
@ -75,10 +75,10 @@ void Video_SendFifoData(u8* _uData)
|
|||||||
if (size + 32 >= FIFO_SIZE)
|
if (size + 32 >= FIFO_SIZE)
|
||||||
{
|
{
|
||||||
int pos = (int)(g_pVideoData-videoBuffer);
|
int pos = (int)(g_pVideoData-videoBuffer);
|
||||||
//if (size-pos > pos)
|
if (size-pos > pos)
|
||||||
//{
|
{
|
||||||
// PanicAlert("FIFO out of bounds (sz = %i, at %08x)", FAKE_GetFifoSize(), readptr);
|
PanicAlert("FIFO out of bounds (sz = %i, at %08x)", size, pos);
|
||||||
//}
|
}
|
||||||
memmove(&videoBuffer[0], &videoBuffer[pos], size - pos );
|
memmove(&videoBuffer[0], &videoBuffer[pos], size - pos );
|
||||||
size -= pos;
|
size -= pos;
|
||||||
g_pVideoData = FAKE_GetFifoStartPtr();
|
g_pVideoData = FAKE_GetFifoStartPtr();
|
||||||
@ -108,7 +108,8 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
|||||||
if (MsgWaitForMultipleObjects(1, &hEventOnIdle, FALSE, 1L, QS_ALLEVENTS) == WAIT_ABANDONED)
|
if (MsgWaitForMultipleObjects(1, &hEventOnIdle, FALSE, 1L, QS_ALLEVENTS) == WAIT_ABANDONED)
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
if (_fifo.CPReadWriteDistance < 1) //fifo.CPLoWatermark)
|
if (_fifo.CPReadWriteDistance < 1)
|
||||||
|
//if (_fifo.CPReadWriteDistance < _fifo.CPLoWatermark)
|
||||||
#if defined(THREAD_VIDEO_WAKEUP_ONIDLE) && defined(_WIN32)
|
#if defined(THREAD_VIDEO_WAKEUP_ONIDLE) && defined(_WIN32)
|
||||||
continue;
|
continue;
|
||||||
#else
|
#else
|
||||||
@ -122,8 +123,6 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
|||||||
#if defined(THREAD_VIDEO_WAKEUP_ONIDLE) && defined(_WIN32)
|
#if defined(THREAD_VIDEO_WAKEUP_ONIDLE) && defined(_WIN32)
|
||||||
while(_fifo.CPReadWriteDistance > 0)
|
while(_fifo.CPReadWriteDistance > 0)
|
||||||
#else
|
#else
|
||||||
//int count = 200;
|
|
||||||
//while(_fifo.CPReadWriteDistance > 0 && count)
|
|
||||||
while(_fifo.bFF_GPReadEnable && (_fifo.CPReadWriteDistance > 0) )// && count)
|
while(_fifo.bFF_GPReadEnable && (_fifo.CPReadWriteDistance > 0) )// && count)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
@ -132,9 +131,9 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
|||||||
{
|
{
|
||||||
if (_fifo.CPReadPointer == _fifo.CPBreakpoint)
|
if (_fifo.CPReadPointer == _fifo.CPBreakpoint)
|
||||||
{
|
{
|
||||||
//_fifo.bFF_Breakpoint = 1;
|
video_initialize.pLog("!!! BP irq raised",FALSE);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
InterlockedExchange((LONG*)&_fifo.bFF_Breakpoint, true);
|
InterlockedExchange((LONG*)&_fifo.bFF_Breakpoint, 1);
|
||||||
#else
|
#else
|
||||||
_fifo.bFF_Breakpoint = true;
|
_fifo.bFF_Breakpoint = true;
|
||||||
#endif
|
#endif
|
||||||
@ -150,8 +149,8 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
|||||||
#else
|
#else
|
||||||
_fifo.sync->Enter();
|
_fifo.sync->Enter();
|
||||||
#endif
|
#endif
|
||||||
//_fifo.CPReadPointer += 32;
|
|
||||||
Video_SendFifoData(uData);
|
Video_SendFifoData(uData);
|
||||||
|
// increase the ReadPtr
|
||||||
u32 readPtr = _fifo.CPReadPointer+32;
|
u32 readPtr = _fifo.CPReadPointer+32;
|
||||||
if (readPtr >= _fifo.CPEnd)
|
if (readPtr >= _fifo.CPEnd)
|
||||||
readPtr = _fifo.CPBase;
|
readPtr = _fifo.CPBase;
|
||||||
@ -164,17 +163,6 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
|||||||
Common::InterlockedExchangeAdd((int*)&_fifo.CPReadWriteDistance, -32);
|
Common::InterlockedExchangeAdd((int*)&_fifo.CPReadWriteDistance, -32);
|
||||||
_fifo.sync->Leave();
|
_fifo.sync->Leave();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// increase the ReadPtr
|
|
||||||
/*if (_fifo.CPReadPointer >= _fifo.CPEnd)
|
|
||||||
{
|
|
||||||
//_fifo.CPReadPointer = _fifo.CPBase;
|
|
||||||
InterlockedExchange((LONG*)&_fifo.CPReadPointer, _fifo.CPBase);
|
|
||||||
//LOG(COMMANDPROCESSOR, "BUFFER LOOP");
|
|
||||||
}/**/
|
|
||||||
#ifndef THREAD_VIDEO_WAKEUP_ONIDLE
|
|
||||||
//count--;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,10 +35,10 @@ typedef struct
|
|||||||
volatile u32 CPReadPointer;
|
volatile u32 CPReadPointer;
|
||||||
volatile u32 CPBreakpoint;
|
volatile u32 CPBreakpoint;
|
||||||
|
|
||||||
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;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// CRITICAL_SECTION sync;
|
// CRITICAL_SECTION sync;
|
||||||
#else
|
#else
|
||||||
|
Reference in New Issue
Block a user