#include #define PPU_CPP namespace SNES { #if defined(DEBUGGER) #include "debugger/debugger.cpp" PPUDebugger ppu; #else PPU ppu; #endif #include "background/background.cpp" #include "mmio/mmio.cpp" #include "screen/screen.cpp" #include "sprite/sprite.cpp" #include "window/window.cpp" #include "serialization.cpp" void PPU::step(unsigned clocks) { clock += clocks; } void PPU::synchronize_cpu() { if(CPU::Threaded == true) { if(clock >= 0) scheduler.resume(cpu.thread); } else { while(clock >= 0) cpu.enter(); } } bool PPU::mosaic_enable() const { return bg1.regs.mosaic || bg2.regs.mosaic || bg3.regs.mosaic || bg4.regs.mosaic; } unsigned PPU::mosaic_vcounter() const { return regs.mosaic_size - regs.mosaic_vcounter; } void PPU::Enter() { ppu.enter(); } void PPU::enter() { while(true) { scheduler.synchronize(); scanline(); add_clocks(28); if(vcounter() <= (!regs.overscan ? 224 : 239)) { for(signed pixel = -7; pixel <= 255; pixel++) { bg1.run(1); bg2.run(1); bg3.run(1); bg4.run(1); add_clocks(2); bg1.run(0); bg2.run(0); bg3.run(0); bg4.run(0); if(pixel >= 0) { oam.run(); window.run(); screen.run(); } add_clocks(2); } add_clocks(14 + 34*2); oam.tilefetch(); } add_clocks(lineclocks() - hcounter()); } } void PPU::add_clocks(unsigned clocks) { clocks >>= 1; while(clocks--) { tick(2); step(2); synchronize_cpu(); } } void PPU::power() { ppu1_version = config().ppu1.version; ppu2_version = config().ppu2.version; for(unsigned i = 0; i < memory::vram.size(); i++) { memory::vram.write(i, random(0)); } for(unsigned i = 0; i < memory::cgram.size(); i++) { memory::cgram.write(i, random(0)); } memset(memory::oam.data(), 0x00, memory::oam.size()); reset(); } void PPU::reset() { create(Enter, system.cpu_frequency()); PPUcounter::reset(); memset(surface, 0, 512 * 512 * sizeof(uint16)); mmio_reset(); bg1.reset(); bg2.reset(); bg3.reset(); bg4.reset(); oam.reset(); window.reset(); screen.reset(); frame(); } void PPU::scanline() { if(vcounter() == 0) { frame(); bg1.frame(); bg2.frame(); bg3.frame(); bg4.frame(); } if(vcounter() == 1) { regs.mosaic_vcounter = mosaic_enable() ? regs.mosaic_size + 1 : 0; } if(regs.mosaic_vcounter && !--regs.mosaic_vcounter) { regs.mosaic_vcounter = mosaic_enable() ? regs.mosaic_size : 0; } bg1.scanline(); bg2.scanline(); bg3.scanline(); bg4.scanline(); oam.scanline(); window.scanline(); screen.scanline(); } void PPU::frame() { system.frame(); oam.frame(); display.interlace = regs.interlace; if (display.overscan && !regs.overscan) memset(output + 225 * 1024, 0, 15 * 1024 * sizeof(uint16)); display.overscan = regs.overscan; } PPU::PPU() : bg1(*this, Background::ID::BG1), bg2(*this, Background::ID::BG2), bg3(*this, Background::ID::BG3), bg4(*this, Background::ID::BG4), oam(*this), window(*this), screen(*this) { surface = new uint16[512 * 512]; output = surface + 16 * 512; } PPU::~PPU() { delete[] surface; } }