mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-06-07 19:41:38 +12:00
Hook up KTimer to scheduler
This commit is contained in:
parent
fa82dad38d
commit
0be099d1ea
7 changed files with 96 additions and 27 deletions
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue