bsnes/higan/md/vdp/vdp.cpp

101 lines
2.0 KiB
C++

#include <md/md.hpp>
namespace MegaDrive {
VDP vdp;
#include "memory.cpp"
#include "io.cpp"
#include "dma.cpp"
#include "render.cpp"
#include "background.cpp"
#include "sprite.cpp"
#include "serialization.cpp"
auto VDP::Enter() -> void {
while(true) scheduler.synchronize(), vdp.main();
}
auto VDP::main() -> void {
scanline();
cpu.lower(CPU::Interrupt::HorizontalBlank);
apu.setINT(false);
if(state.vcounter == 0) {
latch.horizontalInterruptCounter = io.horizontalInterruptCounter;
io.vblankIRQ = false;
cpu.lower(CPU::Interrupt::VerticalBlank);
}
if(state.vcounter == screenHeight()) {
if(io.verticalBlankInterruptEnable) {
io.vblankIRQ = true;
cpu.raise(CPU::Interrupt::VerticalBlank);
}
//todo: should only stay high for ~2573/2 clocks
apu.setINT(true);
}
if(state.vcounter < screenHeight()) {
while(state.hcounter < 1280) {
run();
state.hdot++;
step(pixelWidth());
}
if(latch.horizontalInterruptCounter-- == 0) {
latch.horizontalInterruptCounter = io.horizontalInterruptCounter;
if(io.horizontalBlankInterruptEnable) {
cpu.raise(CPU::Interrupt::HorizontalBlank);
}
}
step(430);
} else {
step(1710);
}
state.hdot = 0;
state.hcounter = 0;
if(++state.vcounter >= frameHeight()) {
state.vcounter = 0;
state.field ^= 1;
latch.overscan = io.overscan;
}
latch.displayWidth = io.displayWidth;
}
auto VDP::step(uint clocks) -> void {
state.hcounter += clocks;
while(clocks--) {
dma.run();
Thread::step(1);
synchronize(cpu);
synchronize(apu);
}
}
auto VDP::refresh() -> void {
auto data = output;
if(!latch.overscan) data -= 16 * 1280;
Emulator::video.refresh(data, 1280 * sizeof(uint32), 1280, 480);
}
auto VDP::power() -> void {
create(VDP::Enter, system.frequency() / 2.0);
output = buffer + 16 * 1280; //overscan offset
io = {};
latch = {};
state = {};
planeA.power();
window.power();
planeB.power();
sprite.power();
dma.power();
}
}