rpcsx/rpcs3/Emu/RSX/NV47/HW/nv406e.cpp
2025-02-11 20:38:35 +01:00

126 lines
3.3 KiB
C++

#include "stdafx.h"
#include "nv406e.h"
#include "nv47_sync.hpp"
#include "Emu/RSX/RSXThread.h"
#include "context_accessors.define.h"
namespace rsx
{
namespace nv406e
{
void set_reference(context* ctx, u32 /*reg*/, u32 arg)
{
RSX(ctx)->sync();
// Write ref+get (get will be written again with the same value at command end)
auto& dma = vm::_ref<RsxDmaControl>(RSX(ctx)->dma_address);
dma.get.release(RSX(ctx)->fifo_ctrl->get_pos());
dma.ref.store(arg);
}
void semaphore_acquire(context* ctx, u32 /*reg*/, u32 arg)
{
RSX(ctx)->sync_point_request.release(true);
const u32 addr = get_address(REGS(ctx)->semaphore_offset_406e(), REGS(ctx)->semaphore_context_dma_406e());
const auto& sema = vm::_ref<RsxSemaphore>(addr).val;
if (sema == arg)
{
// Flip semaphore doesnt need wake-up delay
if (addr != RSX(ctx)->label_addr + 0x10)
{
RSX(ctx)->flush_fifo();
RSX(ctx)->fifo_wake_delay(2);
}
return;
}
else
{
RSX(ctx)->flush_fifo();
}
u64 start = get_system_time();
u64 last_check_val = start;
while (sema != arg)
{
if (RSX(ctx)->test_stopped())
{
RSX(ctx)->state += cpu_flag::again;
return;
}
if (const auto tdr = static_cast<u64>(g_cfg.video.driver_recovery_timeout))
{
const u64 current = get_system_time();
if (current - last_check_val > 20'000)
{
// Suspicious amnount of time has passed
// External pause such as debuggers' pause or operating system sleep may have taken place
// Ignore it
start += current - last_check_val;
}
last_check_val = current;
if ((current - start) > tdr)
{
// If longer than driver timeout force exit
rsx_log.error("nv406e::semaphore_acquire has timed out. semaphore_address=0x%X", addr);
break;
}
}
RSX(ctx)->cpu_wait({});
}
RSX(ctx)->fifo_wake_delay();
RSX(ctx)->performance_counters.idle_time += (get_system_time() - start);
}
void semaphore_release(context* ctx, u32 /*reg*/, u32 arg)
{
const u32 offset = REGS(ctx)->semaphore_offset_406e();
if (offset % 4)
{
rsx_log.warning("NV406E semaphore release is using unaligned semaphore, ignoring. (offset=0x%x)", offset);
return;
}
const u32 ctxt = REGS(ctx)->semaphore_context_dma_406e();
// By avoiding doing this on flip's semaphore release
// We allow last gcm's registers reset to occur in case of a crash
if (const bool is_flip_sema = (offset == 0x10 && ctxt == CELL_GCM_CONTEXT_DMA_SEMAPHORE_R);
!is_flip_sema)
{
RSX(ctx)->sync_point_request.release(true);
}
const u32 addr = get_address(offset, ctxt);
// TODO: Check if possible to write on reservations
if (RSX(ctx)->label_addr >> 28 != addr >> 28)
{
rsx_log.error("NV406E semaphore unexpected address. Please report to the developers. (offset=0x%x, addr=0x%x)", offset, addr);
RSX(ctx)->recover_fifo();
return;
}
if (addr == RSX(ctx)->device_addr + 0x30 && !arg)
{
// HW flip synchronization related, 1 is not written without display queue command (TODO: make it behave as real hw)
arg = 1;
}
util::write_gcm_label<false, true>(ctx, addr, arg);
}
}
}