mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-06-07 19:41:38 +12:00
First stuff running with scheduler
This commit is contained in:
parent
97f97dc6e2
commit
fa82dad38d
5 changed files with 86 additions and 36 deletions
|
@ -2,8 +2,9 @@
|
|||
#include "cpu_dynarmic.hpp"
|
||||
|
||||
#include "arm_defs.hpp"
|
||||
#include "emulator.hpp"
|
||||
|
||||
CPU::CPU(Memory& mem, Kernel& kernel) : mem(mem), env(mem, kernel, scheduler) {
|
||||
CPU::CPU(Memory& mem, Kernel& kernel, Emulator& emu) : mem(mem), emu(emu), scheduler(emu.getScheduler()), env(mem, kernel, emu.getScheduler()) {
|
||||
cp15 = std::make_shared<CP15>();
|
||||
|
||||
Dynarmic::A32::UserConfig config;
|
||||
|
@ -28,12 +29,31 @@ void CPU::reset() {
|
|||
jit->ClearCache();
|
||||
jit->Regs().fill(0);
|
||||
jit->ExtRegs().fill(0);
|
||||
}
|
||||
|
||||
// Reset scheduler and add a VBlank event
|
||||
scheduler.reset();
|
||||
scheduler.addEvent(Scheduler::EventType::VBlank, ticksPerSec / 60);
|
||||
void CPU::runFrame() {
|
||||
emu.frameDone = false;
|
||||
|
||||
printf("%lld\n", scheduler.nextTimestamp);
|
||||
while (!emu.frameDone) {
|
||||
// Run CPU until the next scheduler event
|
||||
env.ticksLeft = scheduler.nextTimestamp;
|
||||
|
||||
execute:
|
||||
const auto exitReason = jit->Run();
|
||||
|
||||
// Handle any scheduler events that need handling.
|
||||
emu.pollScheduler();
|
||||
|
||||
if (static_cast<u32>(exitReason) != 0) [[unlikely]] {
|
||||
// Cache invalidation needs to exit the JIT so it returns a CacheInvalidation HaltReason. In our case, we just go back to executing
|
||||
// The goto might be terrible but it does guarantee that this does not recursively call run and crash, instead getting optimized to a jump
|
||||
if (Dynarmic::Has(exitReason, Dynarmic::HaltReason::CacheInvalidation)) {
|
||||
goto execute;
|
||||
} else {
|
||||
Helpers::panic("Exit reason: %d\nPC: %08X", static_cast<u32>(exitReason), getReg(15));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CPU_DYNARMIC
|
|
@ -17,10 +17,11 @@ __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 1;
|
|||
#endif
|
||||
|
||||
Emulator::Emulator()
|
||||
: config(getConfigPath()), kernel(cpu, memory, gpu, config), cpu(memory, kernel), gpu(memory, config),
|
||||
memory(cpu.getTicksRef(), config), cheats(memory, kernel.getServiceManager().getHID()), lua(memory), running(false), programRunning(false)
|
||||
: config(getConfigPath()), kernel(cpu, memory, gpu, config), cpu(memory, kernel, *this), gpu(memory, config), memory(cpu.getTicksRef(), config),
|
||||
cheats(memory, kernel.getServiceManager().getHID()), lua(memory), running(false), programRunning(false)
|
||||
#ifdef PANDA3DS_ENABLE_HTTP_SERVER
|
||||
, httpServer(this)
|
||||
,
|
||||
httpServer(this)
|
||||
#endif
|
||||
{
|
||||
#ifdef PANDA3DS_ENABLE_DISCORD_RPC
|
||||
|
@ -45,6 +46,10 @@ void Emulator::reset(ReloadOption reload) {
|
|||
cpu.reset();
|
||||
gpu.reset();
|
||||
memory.reset();
|
||||
// Reset scheduler and add a VBlank event
|
||||
scheduler.reset();
|
||||
scheduler.addEvent(Scheduler::EventType::VBlank, CPU::ticksPerSec / 60);
|
||||
|
||||
// Kernel must be reset last because it depends on CPU/Memory state
|
||||
kernel.reset();
|
||||
|
||||
|
@ -99,12 +104,6 @@ void Emulator::runFrame() {
|
|||
if (running) {
|
||||
cpu.runFrame(); // Run 1 frame of instructions
|
||||
gpu.display(); // Display graphics
|
||||
lua.signalEvent(LuaEvent::Frame);
|
||||
|
||||
// Send VBlank interrupts
|
||||
ServiceManager& srv = kernel.getServiceManager();
|
||||
srv.sendGPUInterrupt(GPUInterrupt::VBlank0);
|
||||
srv.sendGPUInterrupt(GPUInterrupt::VBlank1);
|
||||
|
||||
// Run cheats if any are loaded
|
||||
if (cheats.haveCheats()) [[unlikely]] {
|
||||
|
@ -117,6 +116,41 @@ void Emulator::runFrame() {
|
|||
}
|
||||
}
|
||||
|
||||
void Emulator::pollScheduler() {
|
||||
auto& events = scheduler.events;
|
||||
|
||||
// Pop events until there's none pending anymore
|
||||
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());
|
||||
|
||||
scheduler.updateNextTimestamp();
|
||||
|
||||
switch (eventType) {
|
||||
case Scheduler::EventType::VBlank: {
|
||||
// Signal that we've reached the end of a frame
|
||||
frameDone = true;
|
||||
lua.signalEvent(LuaEvent::Frame);
|
||||
|
||||
// Send VBlank interrupts
|
||||
ServiceManager& srv = kernel.getServiceManager();
|
||||
srv.sendGPUInterrupt(GPUInterrupt::VBlank0);
|
||||
srv.sendGPUInterrupt(GPUInterrupt::VBlank1);
|
||||
|
||||
// Queue next VBlank event
|
||||
scheduler.addEvent(Scheduler::EventType::VBlank, time + CPU::ticksPerSec / 60);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
Helpers::panic("Scheduler: Unimplemented event type received: %d\n", static_cast<int>(eventType));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Emulator::loadROM(const std::filesystem::path& path) {
|
||||
// Reset the emulator if we've already loaded a ROM
|
||||
if (romType != ROMType::None) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue