From 1c9a3ac3d3d9414a7e6b270132fe7aacb786a651 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Tue, 2 Jul 2024 15:30:38 +0300 Subject: [PATCH] Add Y2R event delay --- include/kernel/kernel.hpp | 2 ++ include/scheduler.hpp | 3 ++- include/services/service_manager.hpp | 1 + include/services/y2r.hpp | 6 +++++- src/core/kernel/kernel.cpp | 2 ++ src/core/services/y2r.cpp | 32 ++++++++++++++++++++++------ src/emulator.cpp | 2 ++ 7 files changed, 40 insertions(+), 8 deletions(-) diff --git a/include/kernel/kernel.hpp b/include/kernel/kernel.hpp index fc7fe3f3..e0c0651b 100644 --- a/include/kernel/kernel.hpp +++ b/include/kernel/kernel.hpp @@ -15,6 +15,7 @@ #include "services/service_manager.hpp" class CPU; +struct Scheduler; class Kernel { std::span regs; @@ -243,6 +244,7 @@ public: } ServiceManager& getServiceManager() { return serviceManager; } + Scheduler& getScheduler(); void sendGPUInterrupt(GPUInterrupt type) { serviceManager.sendGPUInterrupt(type); } void clearInstructionCache(); diff --git a/include/scheduler.hpp b/include/scheduler.hpp index 97c50afc..cfc4d5e8 100644 --- a/include/scheduler.hpp +++ b/include/scheduler.hpp @@ -11,7 +11,8 @@ struct Scheduler { VBlank = 0, // End of frame event UpdateTimers = 1, // Update kernel timer objects RunDSP = 2, // Make the emulated DSP run for one audio frame - Panic = 3, // Dummy event that is always pending and should never be triggered (Timestamp = UINT64_MAX) + SignalY2R = 3, // Signal that a Y2R conversion has finished + Panic = 4, // Dummy event that is always pending and should never be triggered (Timestamp = UINT64_MAX) TotalNumberOfEvents // How many event types do we have in total? }; static constexpr usize totalNumberOfEvents = static_cast(EventType::TotalNumberOfEvents); diff --git a/include/services/service_manager.hpp b/include/services/service_manager.hpp index 8d1cf381..6679f98d 100644 --- a/include/services/service_manager.hpp +++ b/include/services/service_manager.hpp @@ -109,4 +109,5 @@ class ServiceManager { HIDService& getHID() { return hid; } NFCService& getNFC() { return nfc; } DSPService& getDSP() { return dsp; } + Y2RService& getY2R() { return y2r; } }; diff --git a/include/services/y2r.hpp b/include/services/y2r.hpp index 0cc1d587..4aa96d7b 100644 --- a/include/services/y2r.hpp +++ b/include/services/y2r.hpp @@ -113,8 +113,12 @@ class Y2RService { void startConversion(u32 messagePointer); void stopConversion(u32 messagePointer); -public: + bool isBusy; + + public: Y2RService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {} void reset(); void handleSyncRequest(u32 messagePointer); + + void signalConversionDone(); }; \ No newline at end of file diff --git a/src/core/kernel/kernel.cpp b/src/core/kernel/kernel.cpp index 392b87fd..0d1efc15 100644 --- a/src/core/kernel/kernel.cpp +++ b/src/core/kernel/kernel.cpp @@ -399,3 +399,5 @@ std::string Kernel::getProcessName(u32 pid) { Helpers::panic("Attempted to name non-current process"); } } + +Scheduler& Kernel::getScheduler() { return cpu.getScheduler(); } diff --git a/src/core/services/y2r.cpp b/src/core/services/y2r.cpp index a796631c..ae0961cf 100644 --- a/src/core/services/y2r.cpp +++ b/src/core/services/y2r.cpp @@ -61,6 +61,7 @@ void Y2RService::reset() { inputLineWidth = 420; conversionCoefficients.fill(0); + isBusy = false; } void Y2RService::handleSyncRequest(u32 messagePointer) { @@ -156,6 +157,11 @@ void Y2RService::setTransferEndInterrupt(u32 messagePointer) { void Y2RService::stopConversion(u32 messagePointer) { log("Y2R::StopConversion\n"); + if (isBusy) { + isBusy = false; + kernel.getScheduler().removeEvent(Scheduler::EventType::SignalY2R); + } + mem.write32(messagePointer, IPC::responseHeader(0x27, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -167,7 +173,7 @@ void Y2RService::isBusyConversion(u32 messagePointer) { mem.write32(messagePointer, IPC::responseHeader(0x28, 2, 0)); mem.write32(messagePointer + 4, Result::Success); - mem.write32(messagePointer + 8, static_cast(BusyStatus::NotBusy)); + mem.write32(messagePointer + 8, static_cast(isBusy ? BusyStatus::Busy : BusyStatus::NotBusy)); } void Y2RService::setBlockAlignment(u32 messagePointer) { @@ -434,11 +440,14 @@ void Y2RService::startConversion(u32 messagePointer) { mem.write32(messagePointer, IPC::responseHeader(0x26, 1, 0)); mem.write32(messagePointer + 4, Result::Success); - // Make Y2R conversion end instantly. - // Signal the transfer end event if it's been created. TODO: Is this affected by SetTransferEndInterrupt? - if (transferEndEvent.has_value()) { - kernel.signalEvent(transferEndEvent.value()); - } + // Schedule Y2R conversion end event. + static constexpr u64 delayTicks = 60'000; + isBusy = true; + + // Remove any potential pending Y2R event and schedule a new one + Scheduler& scheduler = kernel.getScheduler(); + scheduler.removeEvent(Scheduler::EventType::SignalY2R); + scheduler.addEvent(Scheduler::EventType::SignalY2R, scheduler.currentTimestamp + delayTicks); } void Y2RService::isFinishedSendingYUV(u32 messagePointer) { @@ -484,4 +493,15 @@ void Y2RService::isFinishedReceiving(u32 messagePointer) { mem.write32(messagePointer, IPC::responseHeader(0x17, 2, 0)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, finished ? 1 : 0); +} + +void Y2RService::signalConversionDone() { + if (isBusy) { + isBusy = false; + + // Signal the transfer end event if it's been created. TODO: Is this affected by SetTransferEndInterrupt? + if (transferEndEvent.has_value()) { + kernel.signalEvent(transferEndEvent.value()); + } + } } \ No newline at end of file diff --git a/src/emulator.cpp b/src/emulator.cpp index 16c3bffd..af156eeb 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -169,6 +169,8 @@ void Emulator::pollScheduler() { break; } + case Scheduler::EventType::SignalY2R: kernel.getServiceManager().getY2R().signalConversionDone(); break; + default: { Helpers::panic("Scheduler: Unimplemented event type received: %d\n", static_cast(eventType)); break;