[GPU] Move VBLANK interrupt to the scheduler

This commit is contained in:
liuk7071 2023-09-09 00:53:18 +02:00
parent 82ff47a1be
commit e79b771a61
4 changed files with 44 additions and 8 deletions

View file

@ -3,13 +3,30 @@
MAKE_LOG_FUNCTION(log, gpuLogger)
void GPU::scanlineEvent(void* classptr) {
GPU* gpu = (GPU*)classptr;
if (gpu->currentScanline < GPUConstants::scanlinesPerVdraw) {
gpu->stat ^= 1 << 31; // Interlacing
}
else if (gpu->currentScanline == GPUConstants::scanlinesPerVdraw) {
gpu->vblank = true;
}
else if (gpu->currentScanline == GPUConstants::scanlinesPerFrame) {
gpu->currentScanline = 0;
}
gpu->currentScanline++;
gpu->scheduler->push(scanlineEvent, gpu->scheduler->time + GPUConstants::cyclesPerScanline, gpu);
}
u32 GPU::getStat() {
// Stubbed
stat |= 1 << 26; // Ready to receive cmd word
stat |= 1 << 27; // Ready to send VRAM to CPU
stat |= 1 << 28; // Ready to receive DMA block
stat |= 1 << 30; // DMA direction CPU -> GP0
stat ^= 1 << 31; // Fake interlacing
return stat;
}

View file

@ -5,14 +5,29 @@
#include <logger.hpp>
#include <backends/software/gpu_software.hpp>
#include <backends/base.hpp>
#include <scheduler.hpp>
namespace GPUConstants {
// TODO: PAL?
constexpr u64 cyclesPerHdraw = 2560 / 1.57;
constexpr u64 cyclesPerScanline = 3413 / 1.57; // NTSC
constexpr u64 scanlinesPerVdraw = 240;
constexpr u64 scanlinesPerFrame = 263;
} // End namespace GPUConstants
class GPU {
public:
GPU() : software(this) {
GPU(Scheduler* scheduler) : software(this), scheduler(scheduler) {
backend = &software;
}
Scheduler* scheduler;
u64 currentScanline = 0;
static void scanlineEvent(void* classptr);
bool vblank = false;
bool uploadingTexture = false;
std::vector<u32> fifo;
u32 getStat();
@ -49,7 +64,6 @@ public:
DisplayMode = 0x08
};
private:
u32 stat = 0x14802000;

View file

@ -3,8 +3,6 @@
#include "playstation.hpp"
int cyclesPerFrame = 521520;
int main(int argc, char** argv) {
if (argc < 2) Helpers::panic("Usage: ChonkyStation [bios path]\n");
@ -22,12 +20,11 @@ int main(int argc, char** argv) {
while (running) {
playstation.cycles = 0;
while (playstation.cycles < cyclesPerFrame)
while (!playstation.getVBLANKAndClear())
playstation.step();
// VBLANK interrupt
playstation.VBLANK();
cyclesPerFrame = 33868800 / 60;
// Handle SDL window events
SDL_Event event;

View file

@ -12,9 +12,12 @@
class PlayStation {
public:
PlayStation(const fs::path& biosPath) : cdrom(), interrupt(), gpu(), dma(), mem(&interrupt, &dma, &gpu, &cdrom), cpu(&mem) {
PlayStation(const fs::path& biosPath) : cdrom(), interrupt(), gpu(&scheduler), dma(), mem(&interrupt, &dma, &gpu, &cdrom), cpu(&mem) {
mem.loadBios(biosPath);
cpu.switchBackend(Cpu::Backend::Interpreter);
// Setup GPU scheduler events
scheduler.push(&gpu.scanlineEvent, scheduler.time + GPUConstants::cyclesPerScanline, &gpu);
}
u64 cycles = 0;
@ -29,6 +32,11 @@ public:
u32 getPC() { return cpu.core.pc; }
u8* getRAM() { return mem.ram; }
u8* getVRAM() { return gpu.getVRAM(); }
bool getVBLANKAndClear() {
bool temp = gpu.vblank;
gpu.vblank = false;
return temp;
}
void VBLANK() { interrupt.raiseInterrupt(Interrupt::InterruptType::VBLANK); }
bool isInBIOS() { return Helpers::inRangeSized<u32>(cpu.core.pc, (u32)Memory::MemoryBase::BIOS, (u32)Memory::MemorySize::BIOS); }