MTVU: Cleaned up GS SIGNAL/LABEL/FINISH communication

This commit is contained in:
TellowKrinkle 2020-12-27 22:30:23 -06:00 committed by tellowkrinkle
parent 527ba52dec
commit 3c2f7983a5
4 changed files with 59 additions and 61 deletions

View File

@ -105,6 +105,7 @@ bool Gif_HandlerAD(u8* pMem)
bool Gif_HandlerAD_MTVU(u8* pMem)
{
// Note: Atomic communication is with MTVU.cpp Get_GSChanges
u32 reg = pMem[8];
u32* data = (u32*)pMem;
@ -125,29 +126,26 @@ bool Gif_HandlerAD_MTVU(u8* pMem)
}
else if (reg == 0x60)
{ // SIGNAL
if (CSRreg.SIGNAL)
{ // Time to ignore all subsequent drawing operations.
GUNIT_WARN("GIF Handler - SIGNAL");
if (vu1Thread.gsInterrupts.load(std::memory_order_acquire) & VU_Thread::InterruptFlagSignal)
Console.Error("GIF Handler MTVU - Double SIGNAL Not Handled");
return 1;
}
else
{
GUNIT_WARN("GIF Handler - SIGNAL");
vu1Thread.gsSignal = ((u64)data[1] << 32) | data[0];
vu1Thread.gsSignalCnt++;
}
vu1Thread.gsSignal.store(((u64)data[1] << 32) | data[0], std::memory_order_relaxed);
vu1Thread.gsInterrupts.fetch_or(VU_Thread::InterruptFlagSignal, std::memory_order_release);
}
else if (reg == 0x61)
{ // FINISH
GUNIT_WARN("GIF Handler - FINISH");
vu1Thread.gsFinish = 1;
u32 old = vu1Thread.gsInterrupts.fetch_or(VU_Thread::InterruptFlagFinish, std::memory_order_relaxed);
if (old & VU_Thread::InterruptFlagFinish)
Console.Error("GIF Handler MTVU - Double FINISH Not Handled");
}
else if (reg == 0x62)
{ // LABEL
GUNIT_WARN("GIF Handler - LABEL");
vu1Thread.gsLabel = ((u64)data[1] << 32) | data[0];
vu1Thread.gsLabelCnt++;
if (vu1Thread.gsLabel.load(std::memory_order_acquire) & VU_Thread::InterruptFlagLabel)
Console.Error("GIF Handler MTVU - Double LABEL Not Handled");
vu1Thread.gsLabel.store(((u64)data[1] << 32) | data[0], std::memory_order_relaxed);
vu1Thread.gsInterrupts.fetch_or(VU_Thread::InterruptFlagLabel, std::memory_order_release);
}
else if (reg >= 0x63 && reg != 0x7f)
{

View File

@ -62,29 +62,18 @@ void SaveStateBase::mtvuFreeze()
unsigned int v = vu1Thread.vuCycles[i].load();
Freeze(v);
}
u32 gsFinishInt;
u64 gsSignals;
u32 gsSignalsCnt;
gsFinishInt = vu1Thread.gsFinish.load();
Freeze(gsFinishInt);
vu1Thread.gsFinish.store(gsFinishInt);
gsSignals = vu1Thread.gsSignal.load();
Freeze(gsSignals);
vu1Thread.gsSignal.store(gsSignals);
gsSignalsCnt = vu1Thread.gsSignalCnt.load();
Freeze(gsSignalsCnt);
vu1Thread.gsSignalCnt.store(gsSignalsCnt);
gsSignals = vu1Thread.gsLabel.load();
Freeze(gsSignals);
vu1Thread.gsLabel.store(gsSignals);
gsSignalsCnt = vu1Thread.gsLabelCnt.load();
Freeze(gsSignalsCnt);
vu1Thread.gsLabelCnt.store(gsSignalsCnt);
u32 gsInterrupts = vu1Thread.gsInterrupts.load();
Freeze(gsInterrupts);
vu1Thread.gsInterrupts.store(gsInterrupts);
u64 gsSignal = vu1Thread.gsSignal.load();
Freeze(gsSignal);
vu1Thread.gsSignal.store(gsSignal);
u64 gsLabel = vu1Thread.gsLabel.load();
Freeze(gsLabel);
vu1Thread.gsLabel.store(gsLabel);
Freeze(vu1Thread.vuCycleIdx);
Freeze(vu1Thread.lastLabel);
Freeze(vu1Thread.lastSignal);
}
VU_Thread::VU_Thread(BaseVUmicroCPU*& _vuCPU, VURegs& _vuRegs)
@ -109,8 +98,6 @@ void VU_Thread::Reset()
ScopedLock lock(mtxBusy);
vuCycleIdx = 0;
lastLabel = 0;
lastSignal = 0;
isBusy = false;
m_ato_write_pos = 0;
m_write_pos = 0;
@ -120,8 +107,7 @@ void VU_Thread::Reset()
memzero(vifRegs);
for (size_t i = 0; i < 4; ++i)
vu1Thread.vuCycles[i] = 0;
vu1Thread.gsSignal = 0;
vu1Thread.gsLabel = 0;
vu1Thread.gsInterrupts = 0;
}
void VU_Thread::ExecuteTaskInThread()
@ -346,17 +332,32 @@ u32 VU_Thread::Get_vuCycles()
void VU_Thread::Get_GSChanges()
{
u32 finishInt = gsFinish.load(std::memory_order_acquire);
u64 signalCnt = gsSignalCnt.load(std::memory_order_acquire);
u64 labelCnt = gsLabelCnt.load(std::memory_order_acquire);
// Note: Atomic communication is with Gif_Unit.cpp Gif_HandlerAD_MTVU
u32 interrupts = gsInterrupts.load(std::memory_order_relaxed);
if (!interrupts)
return;
// We don't support stacking multiple of the same type of interrupt, so the faster we read the required data and clear the flag the less likely we'll run into issues with that
u64 signal, label;
if (interrupts & (InterruptFlagSignal | InterruptFlagLabel))
{
// label and signal access other variables so the load must have acquire semantics
std::atomic_thread_fence(std::memory_order_acquire);
signal = gsSignal.load(std::memory_order_relaxed);
label = gsLabel.load(std::memory_order_relaxed);
// Also need release semantics on the clear
gsInterrupts.fetch_and(~interrupts, std::memory_order_release);
}
else
{
gsInterrupts.fetch_and(~interrupts, std::memory_order_relaxed);
}
if (signalCnt != lastSignal)
if (interrupts & InterruptFlagSignal)
{
GUNIT_WARN("SIGNAL firing");
const u64 signal = gsSignal.load(std::memory_order_acquire);
const u32 signalMsk = (u32)(signal >> 32);
const u32 signalData = (u32)signal;
lastSignal = signalCnt;
if (CSRreg.SIGNAL)
{
GUNIT_WARN("Queue SIGNAL");
@ -374,7 +375,7 @@ void VU_Thread::Get_GSChanges()
gsIrq();
}
}
if (finishInt)
if (interrupts & InterruptFlagFinish)
{
GUNIT_WARN("Finish firing");
CSRreg.FINISH = true;
@ -382,16 +383,12 @@ void VU_Thread::Get_GSChanges()
if (!gifRegs.stat.APATH)
Gif_FinishIRQ();
gsFinish.store(0);
}
if (labelCnt != lastLabel)
if (interrupts & InterruptFlagLabel)
{
GUNIT_WARN("LABEL firing");
const u64 label = gsLabel.load(std::memory_order_acquire);
const u32 labelMsk = (u32)(label >> 32);
const u32 labelData = (u32)label;
lastLabel = labelCnt;
GSSIGLBLID.LBLID = (GSSIGLBLID.LBLID & ~labelMsk) | (labelData & labelMsk);
}
}

View File

@ -44,16 +44,19 @@ class VU_Thread : public pxThread {
public:
__aligned16 vifStruct vif;
__aligned16 VIFregisters vifRegs;
__aligned(4) Semaphore semaXGkick;
__aligned(4) std::atomic<unsigned int> vuCycles[4]; // Used for VU cycle stealing hack
__aligned(4) u32 vuCycleIdx; // Used for VU cycle stealing hack
__aligned(4) u32 lastSignal;
__aligned(4) u32 lastLabel;
__aligned(4) std::atomic<unsigned int> gsFinish; // Used for GS Signal, Finish etc
__aligned(4) std::atomic<u32> gsLabelCnt; // Used for GS Label command
__aligned(4) std::atomic<u32> gsSignalCnt; // Used for GS Signal command
__aligned(4) std::atomic<u64> gsLabel; // Used for GS Label command
__aligned(4) std::atomic<u64> gsSignal; // Used for GS Signal command
Semaphore semaXGkick;
std::atomic<unsigned int> vuCycles[4]; // Used for VU cycle stealing hack
u32 vuCycleIdx; // Used for VU cycle stealing hack
enum InterruptFlag {
InterruptFlagFinish = 1 << 0,
InterruptFlagSignal = 1 << 1,
InterruptFlagLabel = 1 << 2,
};
std::atomic<u32> gsInterrupts; // Used for GS Signal, Finish etc
std::atomic<u64> gsLabel; // Used for GS Label command
std::atomic<u64> gsSignal; // Used for GS Signal command
VU_Thread(BaseVUmicroCPU*& _vuCPU, VURegs& _vuRegs);
virtual ~VU_Thread();

View File

@ -24,7 +24,7 @@
// the lower 16 bit value. IF the change is breaking of all compatibility with old
// states, increment the upper 16 bit value, and clear the lower 16 bits to 0.
static const u32 g_SaveVersion = (0x9A14 << 16) | 0x0000;
static const u32 g_SaveVersion = (0x9A15 << 16) | 0x0000;
// this function is meant to be used in the place of GSfreeze, and provides a safe layer
// between the GS saving function and the MTGS's needs. :)