From 270ef3e0d266b91c64c174702933d57c5cf963c2 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Sun, 30 Oct 2022 16:37:37 +0000 Subject: [PATCH] Implement GPFIFO semaphore acquire operations --- .../cpp/skyline/soc/gm20b/engines/gpfifo.cpp | 105 +++++++++++------- 1 file changed, 64 insertions(+), 41 deletions(-) diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/gpfifo.cpp b/app/src/main/cpp/skyline/soc/gm20b/engines/gpfifo.cpp index f447a990..1b760ef2 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/gpfifo.cpp +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/gpfifo.cpp @@ -41,49 +41,72 @@ namespace skyline::soc::gm20b::engine { channelCtx.asCtx->gmmu.Write(address + 8, GetGpuTimeTicks()); } - if (action.operation == Registers::Semaphore::Operation::Release) { - channelCtx.asCtx->gmmu.Write(address, registers.semaphore->payload); - Logger::Debug("SemaphoreRelease: address: 0x{:X} payload: {}", address, registers.semaphore->payload); - } else if (action.operation == Registers::Semaphore::Operation::Reduction) { - u32 origVal{channelCtx.asCtx->gmmu.Read(address)}; - bool isSigned{action.format == Registers::Semaphore::Format::Signed}; + switch (action.operation) { + case Registers::Semaphore::Operation::Acquire: + Logger::Debug("Acquire semaphore: 0x{:X} payload: {}", address, registers.semaphore->payload); + channelCtx.Unlock(); - // https://github.com/NVIDIA/open-gpu-doc/blob/b7d1bd16fe62135ebaec306b39dfdbd9e5657827/manuals/turing/tu104/dev_pbdma.ref.txt#L3549 - u32 val{[](Registers::Semaphore::Reduction reduction, u32 origVal, u32 payload, bool isSigned) { - switch (reduction) { - case Registers::Semaphore::Reduction::Min: - if (isSigned) - return static_cast(std::min(static_cast(origVal), static_cast(payload))); - else - return std::min(origVal, payload); - case Registers::Semaphore::Reduction::Max: - if (isSigned) - return static_cast(std::max(static_cast(origVal), static_cast(payload))); - else - return std::max(origVal, payload); - case Registers::Semaphore::Reduction::Xor: - return origVal ^ payload; - case Registers::Semaphore::Reduction::And: - return origVal & payload; - case Registers::Semaphore::Reduction::Or: - return origVal | payload; - case Registers::Semaphore::Reduction::Add: - if (isSigned) - return static_cast(static_cast(origVal) + static_cast(payload)); - else - return origVal + payload; - case Registers::Semaphore::Reduction::Inc: - return (origVal >= payload) ? 0 : origVal + 1; - case Registers::Semaphore::Reduction::Dec: - return (origVal == 0 || origVal > payload) ? payload : origVal - 1; - } - }(registers.semaphore->action.reduction, origVal, registers.semaphore->payload, isSigned)}; - Logger::Debug("SemaphoreReduction: address: 0x{:X} op: {} payload: {} original value: {} reduced value: {}", - address, static_cast(registers.semaphore->action.reduction), registers.semaphore->payload, origVal, val); + while (channelCtx.asCtx->gmmu.Read(address) != registers.semaphore->payload) + std::this_thread::yield(); - channelCtx.asCtx->gmmu.Write(address, val); - } else { - Logger::Warn("Unimplemented semaphore operation: 0x{:X}", static_cast(registers.semaphore->action.operation)); + channelCtx.Lock(); + break; + case Registers::Semaphore::Operation::Release: + channelCtx.asCtx->gmmu.Write(address, registers.semaphore->payload); + Logger::Debug("SemaphoreRelease: address: 0x{:X} payload: {}", address, registers.semaphore->payload); + break; + case Registers::Semaphore::Operation::AcqGeq : + Logger::Debug("Acquire semaphore: 0x{:X} payload: {}", address, registers.semaphore->payload); + channelCtx.Unlock(); + + while (channelCtx.asCtx->gmmu.Read(address) < registers.semaphore->payload) + std::this_thread::yield(); + + channelCtx.Lock(); + break; + case Registers::Semaphore::Operation::Reduction: { + u32 origVal{channelCtx.asCtx->gmmu.Read(address)}; + bool isSigned{action.format == Registers::Semaphore::Format::Signed}; + + // https://github.com/NVIDIA/open-gpu-doc/blob/b7d1bd16fe62135ebaec306b39dfdbd9e5657827/manuals/turing/tu104/dev_pbdma.ref.txt#L3549 + u32 val{[](Registers::Semaphore::Reduction reduction, u32 origVal, u32 payload, bool isSigned) { + switch (reduction) { + case Registers::Semaphore::Reduction::Min: + if (isSigned) + return static_cast(std::min(static_cast(origVal), static_cast(payload))); + else + return std::min(origVal, payload); + case Registers::Semaphore::Reduction::Max: + if (isSigned) + return static_cast(std::max(static_cast(origVal), static_cast(payload))); + else + return std::max(origVal, payload); + case Registers::Semaphore::Reduction::Xor: + return origVal ^ payload; + case Registers::Semaphore::Reduction::And: + return origVal & payload; + case Registers::Semaphore::Reduction::Or: + return origVal | payload; + case Registers::Semaphore::Reduction::Add: + if (isSigned) + return static_cast(static_cast(origVal) + static_cast(payload)); + else + return origVal + payload; + case Registers::Semaphore::Reduction::Inc: + return (origVal >= payload) ? 0 : origVal + 1; + case Registers::Semaphore::Reduction::Dec: + return (origVal == 0 || origVal > payload) ? payload : origVal - 1; + } + }(registers.semaphore->action.reduction, origVal, registers.semaphore->payload, isSigned)}; + Logger::Debug("SemaphoreReduction: address: 0x{:X} op: {} payload: {} original value: {} reduced value: {}", + address, static_cast(registers.semaphore->action.reduction), registers.semaphore->payload, origVal, val); + + channelCtx.asCtx->gmmu.Write(address, val); + break; + } + default: + Logger::Warn("Unimplemented semaphore operation: 0x{:X}", static_cast(registers.semaphore->action.operation)); + break; } }) }