Merge pull request #2465 from lioncash/commandproc

CommandProcessor: Replace volatile usages with atomics
This commit is contained in:
Markus Wick 2015-05-27 11:07:36 +02:00
commit 255a8dfdd2
4 changed files with 78 additions and 40 deletions

View File

@ -2,6 +2,8 @@
// Licensed under GPLv2+ // Licensed under GPLv2+
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <atomic>
#include "Common/Atomic.h" #include "Common/Atomic.h"
#include "Common/ChunkFile.h" #include "Common/ChunkFile.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
@ -40,15 +42,15 @@ static u16 m_bboxright;
static u16 m_bboxbottom; static u16 m_bboxbottom;
static u16 m_tokenReg; static u16 m_tokenReg;
volatile bool interruptSet= false; static std::atomic<bool> s_interrupt_set;
volatile bool interruptWaiting= false; static std::atomic<bool> s_interrupt_waiting;
volatile bool interruptTokenWaiting = false; static std::atomic<bool> s_interrupt_token_waiting;
volatile bool interruptFinishWaiting = false; static std::atomic<bool> s_interrupt_finish_waiting;
static std::atomic<u32> s_vi_ticks(CommandProcessor::m_cpClockOrigin);
Common::Flag s_gpuMaySleep; Common::Flag s_gpuMaySleep;
volatile u32 VITicks = CommandProcessor::m_cpClockOrigin;
static bool IsOnThread() static bool IsOnThread()
{ {
return SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread; return SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread;
@ -71,10 +73,10 @@ void DoState(PointerWrap &p)
p.Do(m_tokenReg); p.Do(m_tokenReg);
p.Do(fifo); p.Do(fifo);
p.Do(interruptSet); p.Do(s_interrupt_set);
p.Do(interruptWaiting); p.Do(s_interrupt_waiting);
p.Do(interruptTokenWaiting); p.Do(s_interrupt_token_waiting);
p.Do(interruptFinishWaiting); p.Do(s_interrupt_finish_waiting);
} }
static inline void WriteLow(volatile u32& _reg, u16 lowbits) static inline void WriteLow(volatile u32& _reg, u16 lowbits)
@ -118,10 +120,10 @@ void Init()
fifo.bFF_LoWatermark = 0; fifo.bFF_LoWatermark = 0;
fifo.bFF_LoWatermarkInt = 0; fifo.bFF_LoWatermarkInt = 0;
interruptSet = false; s_interrupt_set.store(false);
interruptWaiting = false; s_interrupt_waiting.store(false);
interruptFinishWaiting = false; s_interrupt_finish_waiting.store(false);
interruptTokenWaiting = false; s_interrupt_token_waiting.store(false);
et_UpdateInterrupts = CoreTiming::RegisterEvent("CPInterrupt", UpdateInterrupts_Wrapper); et_UpdateInterrupts = CoreTiming::RegisterEvent("CPInterrupt", UpdateInterrupts_Wrapper);
} }
@ -358,18 +360,18 @@ void UpdateInterrupts(u64 userdata)
{ {
if (userdata) if (userdata)
{ {
interruptSet = true; s_interrupt_set.store(true);
INFO_LOG(COMMANDPROCESSOR,"Interrupt set"); INFO_LOG(COMMANDPROCESSOR,"Interrupt set");
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true); ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true);
} }
else else
{ {
interruptSet = false; s_interrupt_set.store(false);
INFO_LOG(COMMANDPROCESSOR,"Interrupt cleared"); INFO_LOG(COMMANDPROCESSOR,"Interrupt cleared");
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, false); ProcessorInterface::SetInterrupt(INT_CAUSE_CP, false);
} }
CoreTiming::ForceExceptionCheck(0); CoreTiming::ForceExceptionCheck(0);
interruptWaiting = false; s_interrupt_waiting.store(false);
RunGpu(); RunGpu();
} }
@ -379,6 +381,21 @@ void UpdateInterruptsFromVideoBackend(u64 userdata)
CoreTiming::ScheduleEvent_Threadsafe(0, et_UpdateInterrupts, userdata); CoreTiming::ScheduleEvent_Threadsafe(0, et_UpdateInterrupts, userdata);
} }
bool IsInterruptWaiting()
{
return s_interrupt_waiting.load();
}
void SetInterruptTokenWaiting(bool waiting)
{
s_interrupt_token_waiting.store(waiting);
}
void SetInterruptFinishWaiting(bool waiting)
{
s_interrupt_finish_waiting.store(waiting);
}
void SetCPStatusFromGPU() void SetCPStatusFromGPU()
{ {
// breakpoint // breakpoint
@ -416,7 +433,7 @@ void SetCPStatusFromGPU()
bool interrupt = (bpInt || ovfInt || undfInt) && m_CPCtrlReg.GPReadEnable; bool interrupt = (bpInt || ovfInt || undfInt) && m_CPCtrlReg.GPReadEnable;
if (interrupt != interruptSet && !interruptWaiting) if (interrupt != s_interrupt_set.load() && !s_interrupt_waiting.load())
{ {
u64 userdata = interrupt ? 1 : 0; u64 userdata = interrupt ? 1 : 0;
if (IsOnThread()) if (IsOnThread())
@ -424,7 +441,7 @@ void SetCPStatusFromGPU()
if (!interrupt || bpInt || undfInt || ovfInt) if (!interrupt || bpInt || undfInt || ovfInt)
{ {
// Schedule the interrupt asynchronously // Schedule the interrupt asynchronously
interruptWaiting = true; s_interrupt_waiting.store(true);
CommandProcessor::UpdateInterruptsFromVideoBackend(userdata); CommandProcessor::UpdateInterruptsFromVideoBackend(userdata);
} }
} }
@ -447,14 +464,14 @@ void SetCPStatusFromCPU()
bool interrupt = (bpInt || ovfInt || undfInt) && m_CPCtrlReg.GPReadEnable; bool interrupt = (bpInt || ovfInt || undfInt) && m_CPCtrlReg.GPReadEnable;
if (interrupt != interruptSet && !interruptWaiting) if (interrupt != s_interrupt_set.load() && !s_interrupt_waiting.load())
{ {
u64 userdata = interrupt ? 1 : 0; u64 userdata = interrupt ? 1 : 0;
if (IsOnThread()) if (IsOnThread())
{ {
if (!interrupt || bpInt || undfInt || ovfInt) if (!interrupt || bpInt || undfInt || ovfInt)
{ {
interruptSet = interrupt; s_interrupt_set.store(interrupt);
INFO_LOG(COMMANDPROCESSOR,"Interrupt set"); INFO_LOG(COMMANDPROCESSOR,"Interrupt set");
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, interrupt); ProcessorInterface::SetInterrupt(INT_CAUSE_CP, interrupt);
} }
@ -468,7 +485,7 @@ void SetCPStatusFromCPU()
void ProcessFifoEvents() void ProcessFifoEvents()
{ {
if (IsOnThread() && (interruptWaiting || interruptFinishWaiting || interruptTokenWaiting)) if (IsOnThread() && (s_interrupt_waiting.load() || s_interrupt_finish_waiting.load() || s_interrupt_token_waiting.load()))
CoreTiming::ProcessFifoWaitEvents(); CoreTiming::ProcessFifoWaitEvents();
} }
@ -533,12 +550,28 @@ void SetCpClearRegister()
void Update() void Update()
{ {
while (VITicks > m_cpClockOrigin && fifo.isGpuReadingData && IsOnThread()) while (s_vi_ticks.load() > m_cpClockOrigin && fifo.isGpuReadingData && IsOnThread())
Common::YieldCPU(); Common::YieldCPU();
if (fifo.isGpuReadingData) if (fifo.isGpuReadingData)
Common::AtomicAdd(VITicks, SystemTimers::GetTicksPerSecond() / 10000); s_vi_ticks.fetch_add(SystemTimers::GetTicksPerSecond() / 10000);
RunGpu(); RunGpu();
} }
u32 GetVITicks()
{
return s_vi_ticks.load();
}
void SetVITicks(u32 ticks)
{
s_vi_ticks.store(ticks);
}
void DecrementVITicks(u32 ticks)
{
s_vi_ticks.fetch_sub(ticks);
}
} // end of namespace CommandProcessor } // end of namespace CommandProcessor

View File

@ -17,11 +17,6 @@ namespace CommandProcessor
{ {
extern SCPFifoStruct fifo; //This one is shared between gfx thread and emulator thread. extern SCPFifoStruct fifo; //This one is shared between gfx thread and emulator thread.
extern volatile bool interruptSet;
extern volatile bool interruptWaiting;
extern volatile bool interruptTokenWaiting;
extern volatile bool interruptFinishWaiting;
extern Common::Flag s_gpuMaySleep; extern Common::Flag s_gpuMaySleep;
// internal hardware addresses // internal hardware addresses
@ -143,12 +138,19 @@ void GatherPipeBursted();
void UpdateInterrupts(u64 userdata); void UpdateInterrupts(u64 userdata);
void UpdateInterruptsFromVideoBackend(u64 userdata); void UpdateInterruptsFromVideoBackend(u64 userdata);
bool IsInterruptWaiting();
void SetInterruptTokenWaiting(bool waiting);
void SetInterruptFinishWaiting(bool waiting);
void SetCpClearRegister(); void SetCpClearRegister();
void SetCpControlRegister(); void SetCpControlRegister();
void SetCpStatusRegister(); void SetCpStatusRegister();
void ProcessFifoEvents(); void ProcessFifoEvents();
void Update(); void Update();
extern volatile u32 VITicks;
u32 GetVITicks();
void SetVITicks(u32 ticks);
void DecrementVITicks(u32 ticks);
} // namespace CommandProcessor } // namespace CommandProcessor

View File

@ -103,7 +103,7 @@ void Fifo_Init()
s_video_buffer = (u8*)AllocateMemoryPages(FIFO_SIZE + 4); s_video_buffer = (u8*)AllocateMemoryPages(FIFO_SIZE + 4);
ResetVideoBuffer(); ResetVideoBuffer();
s_gpu_running_state.store(false); s_gpu_running_state.store(false);
Common::AtomicStore(CommandProcessor::VITicks, CommandProcessor::m_cpClockOrigin); CommandProcessor::SetVITicks(CommandProcessor::m_cpClockOrigin);
} }
void Fifo_Shutdown() void Fifo_Shutdown()
@ -321,17 +321,17 @@ void RunGpuLoop()
if (!fifo.isGpuReadingData) if (!fifo.isGpuReadingData)
{ {
Common::AtomicStore(CommandProcessor::VITicks, CommandProcessor::m_cpClockOrigin); CommandProcessor::SetVITicks(CommandProcessor::m_cpClockOrigin);
} }
bool run_loop = true; bool run_loop = true;
// check if we are able to run this buffer // check if we are able to run this buffer
while (run_loop && !CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint()) while (run_loop && !CommandProcessor::IsInterruptWaiting() && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint())
{ {
fifo.isGpuReadingData = true; fifo.isGpuReadingData = true;
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bSyncGPU || Common::AtomicLoad(CommandProcessor::VITicks) > CommandProcessor::m_cpClockOrigin) if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bSyncGPU || CommandProcessor::GetVITicks() > CommandProcessor::m_cpClockOrigin)
{ {
u32 readPtr = fifo.CPReadPointer; u32 readPtr = fifo.CPReadPointer;
ReadDataFromFifo(readPtr); ReadDataFromFifo(readPtr);
@ -349,8 +349,8 @@ void RunGpuLoop()
s_video_buffer_read_ptr = OpcodeDecoder_Run(DataReader(s_video_buffer_read_ptr, write_ptr), &cyclesExecuted, false); s_video_buffer_read_ptr = OpcodeDecoder_Run(DataReader(s_video_buffer_read_ptr, write_ptr), &cyclesExecuted, false);
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSyncGPU && Common::AtomicLoad(CommandProcessor::VITicks) >= cyclesExecuted) if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSyncGPU && CommandProcessor::GetVITicks() >= cyclesExecuted)
Common::AtomicAdd(CommandProcessor::VITicks, -(s32)cyclesExecuted); CommandProcessor::DecrementVITicks(cyclesExecuted);
Common::AtomicStore(fifo.CPReadPointer, readPtr); Common::AtomicStore(fifo.CPReadPointer, readPtr);
Common::AtomicAdd(fifo.CPReadWriteDistance, -32); Common::AtomicAdd(fifo.CPReadWriteDistance, -32);

View File

@ -274,14 +274,14 @@ void SetToken_OnMainThread(u64 userdata, int cyclesLate)
s_signal_token_interrupt.store(1); s_signal_token_interrupt.store(1);
UpdateInterrupts(); UpdateInterrupts();
} }
CommandProcessor::interruptTokenWaiting = false; CommandProcessor::SetInterruptTokenWaiting(false);
} }
void SetFinish_OnMainThread(u64 userdata, int cyclesLate) void SetFinish_OnMainThread(u64 userdata, int cyclesLate)
{ {
s_signal_finish_interrupt.store(1); s_signal_finish_interrupt.store(1);
UpdateInterrupts(); UpdateInterrupts();
CommandProcessor::interruptFinishWaiting = false; CommandProcessor::SetInterruptFinishWaiting(false);
} }
// SetToken // SetToken
@ -293,7 +293,8 @@ void SetToken(const u16 _token, const int _bSetTokenAcknowledge)
s_signal_token_interrupt.store(1); s_signal_token_interrupt.store(1);
} }
CommandProcessor::interruptTokenWaiting = true; CommandProcessor::SetInterruptTokenWaiting(true);
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread || g_use_deterministic_gpu_thread) if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread || g_use_deterministic_gpu_thread)
CoreTiming::ScheduleEvent(0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16)); CoreTiming::ScheduleEvent(0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16));
else else
@ -304,11 +305,13 @@ void SetToken(const u16 _token, const int _bSetTokenAcknowledge)
// THIS IS EXECUTED FROM VIDEO THREAD (BPStructs.cpp) when a new frame has been drawn // THIS IS EXECUTED FROM VIDEO THREAD (BPStructs.cpp) when a new frame has been drawn
void SetFinish() void SetFinish()
{ {
CommandProcessor::interruptFinishWaiting = true; CommandProcessor::SetInterruptFinishWaiting(true);
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread || g_use_deterministic_gpu_thread) if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread || g_use_deterministic_gpu_thread)
CoreTiming::ScheduleEvent(0, et_SetFinishOnMainThread, 0); CoreTiming::ScheduleEvent(0, et_SetFinishOnMainThread, 0);
else else
CoreTiming::ScheduleEvent_Threadsafe(0, et_SetFinishOnMainThread, 0); CoreTiming::ScheduleEvent_Threadsafe(0, et_SetFinishOnMainThread, 0);
INFO_LOG(PIXELENGINE, "VIDEO Set Finish"); INFO_LOG(PIXELENGINE, "VIDEO Set Finish");
} }