Hook up KTimer to scheduler

This commit is contained in:
wheremyfoodat 2024-01-22 04:04:05 +02:00
parent fa82dad38d
commit 0be099d1ea
7 changed files with 96 additions and 27 deletions

View file

@ -36,7 +36,7 @@ void CPU::runFrame() {
while (!emu.frameDone) {
// Run CPU until the next scheduler event
env.ticksLeft = scheduler.nextTimestamp;
env.ticksLeft = scheduler.nextTimestamp - scheduler.currentTimestamp;
execute:
const auto exitReason = jit->Run();
@ -54,6 +54,8 @@ void CPU::runFrame() {
}
}
}
printf("CPU END!\n");
}
#endif // CPU_DYNARMIC

View file

@ -1,5 +1,8 @@
#include "kernel.hpp"
#include <limits>
#include "cpu.hpp"
#include "kernel.hpp"
#include "scheduler.hpp"
Handle Kernel::makeTimer(ResetType type) {
Handle ret = makeObject(KernelObjectType::Timer);
@ -13,30 +16,48 @@ Handle Kernel::makeTimer(ResetType type) {
return ret;
}
void Kernel::updateTimer(Handle handle, Timer* timer) {
if (timer->running) {
const u64 currentTicks = cpu.getTicks();
u64 elapsedTicks = currentTicks - timer->startTick;
void Kernel::pollTimers() {
u64 currentTick = cpu.getTicks();
constexpr double ticksPerSec = double(CPU::ticksPerSec);
constexpr double nsPerTick = ticksPerSec / 1000000000.0;
const s64 elapsedNs = s64(double(elapsedTicks) * nsPerTick);
// Find the next timestamp we'll poll KTimers on. To do this, we find the minimum tick one of our timers will fire
u64 nextTimestamp = std::numeric_limits<u64>::max();
// Do we have any active timers anymore? If not, then we won't need to schedule a new timer poll event
bool haveActiveTimers = false;
// Timer has fired
if (elapsedNs >= timer->currentDelay) {
timer->startTick = currentTicks;
timer->currentDelay = timer->interval;
signalTimer(handle, timer);
for (auto handle : timerHandles) {
KernelObject* object = getObject(handle, KernelObjectType::Timer);
if (object != nullptr) {
Timer* timer = object->getData<Timer>();
if (timer->running) {
// If timer has fired, signal it and set the tick it will next time
if (currentTick >= timer->fireTick) {
signalTimer(handle, timer);
}
// Update our next timer fire timestamp and mark that we should schedule a new event to poll timers
// We recheck timer->running because signalling a timer stops it if interval == 0
if (timer->running) {
nextTimestamp = std::min<u64>(nextTimestamp, timer->fireTick);
haveActiveTimers = true;
}
}
}
}
// If we still have active timers, schedule next poll event
if (haveActiveTimers) {
Scheduler& scheduler = cpu.getScheduler();
scheduler.addEvent(Scheduler::EventType::UpdateTimers, nextTimestamp);
}
}
void Kernel::cancelTimer(Timer* timer) {
timer->running = false;
// TODO: When we have a scheduler this should properly cancel timer events in the scheduler
}
void Kernel::signalTimer(Handle timerHandle, Timer* timer) {
printf("DEEPFRIED\n");
timer->fired = true;
requireReschedule();
@ -54,6 +75,8 @@ void Kernel::signalTimer(Handle timerHandle, Timer* timer) {
if (timer->interval == 0) {
cancelTimer(timer);
} else {
timer->fireTick = cpu.getTicks() + Scheduler::nsToCycles(timer->interval);
}
}
@ -87,18 +110,20 @@ void Kernel::svcSetTimer() {
Timer* timer = object->getData<Timer>();
cancelTimer(timer);
timer->currentDelay = initial;
timer->interval = interval;
timer->running = true;
timer->startTick = cpu.getTicks();
timer->fireTick = cpu.getTicks() + Scheduler::nsToCycles(initial);
Scheduler& scheduler = cpu.getScheduler();
// Signal an event to poll timers as soon as possible
scheduler.removeEvent(Scheduler::EventType::UpdateTimers);
scheduler.addEvent(Scheduler::EventType::UpdateTimers, cpu.getTicks() + 1);
// If the initial delay is 0 then instantly signal the timer
if (initial == 0) {
signalTimer(handle, timer);
} else {
// This should schedule an event in the scheduler when we have one
}
regs[0] = Result::Success;
}

View file

@ -120,7 +120,7 @@ void Emulator::pollScheduler() {
auto& events = scheduler.events;
// Pop events until there's none pending anymore
while (scheduler.currentTimestamp > scheduler.nextTimestamp) {
while (scheduler.currentTimestamp >= scheduler.nextTimestamp) {
// Read event timestamp and type, pop it from the scheduler and handle it
auto [time, eventType] = std::move(*events.begin());
events.erase(events.begin());
@ -129,6 +129,7 @@ void Emulator::pollScheduler() {
switch (eventType) {
case Scheduler::EventType::VBlank: {
printf("VBLANK!!!!!!\n");
// Signal that we've reached the end of a frame
frameDone = true;
lua.signalEvent(LuaEvent::Frame);
@ -143,6 +144,8 @@ void Emulator::pollScheduler() {
break;
}
case Scheduler::EventType::UpdateTimers: kernel.pollTimers(); break;
default: {
Helpers::panic("Scheduler: Unimplemented event type received: %d\n", static_cast<int>(eventType));
break;