2010-09-01 13:18:10 +00:00
|
|
|
#include <snes.hpp>
|
|
|
|
|
|
|
|
#define PPU_CPP
|
|
|
|
namespace SNES {
|
|
|
|
|
|
|
|
PPU ppu;
|
|
|
|
|
|
|
|
#include "mmio/mmio.cpp"
|
2010-09-01 13:22:05 +00:00
|
|
|
#include "window/window.cpp"
|
2010-09-01 13:20:05 +00:00
|
|
|
#include "cache/cache.cpp"
|
|
|
|
#include "background/background.cpp"
|
|
|
|
#include "sprite/sprite.cpp"
|
2010-09-01 13:18:10 +00:00
|
|
|
#include "screen/screen.cpp"
|
|
|
|
#include "serialization.cpp"
|
|
|
|
|
|
|
|
void PPU::step(unsigned clocks) {
|
|
|
|
clock += clocks;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PPU::synchronize_cpu() {
|
|
|
|
if(CPU::Threaded == true) {
|
|
|
|
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
|
|
|
|
} else {
|
|
|
|
while(clock >= 0) cpu.enter();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PPU::Enter() { ppu.enter(); }
|
|
|
|
|
|
|
|
void PPU::enter() {
|
|
|
|
while(true) {
|
|
|
|
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
|
|
|
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
scanline();
|
2010-09-01 13:22:05 +00:00
|
|
|
if(vcounter() < display.height && vcounter()) {
|
2010-09-01 13:18:10 +00:00
|
|
|
add_clocks(512);
|
|
|
|
render_scanline();
|
|
|
|
add_clocks(lineclocks() - 512);
|
|
|
|
} else {
|
|
|
|
add_clocks(lineclocks());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PPU::add_clocks(unsigned clocks) {
|
|
|
|
tick(clocks);
|
|
|
|
step(clocks);
|
|
|
|
synchronize_cpu();
|
|
|
|
}
|
|
|
|
|
|
|
|
void PPU::render_scanline() {
|
|
|
|
if(regs.display_disable) return screen.render_black();
|
2010-09-01 13:20:05 +00:00
|
|
|
screen.scanline();
|
|
|
|
bg1.render();
|
|
|
|
bg2.render();
|
|
|
|
bg3.render();
|
|
|
|
bg4.render();
|
|
|
|
oam.render();
|
2010-09-01 13:18:10 +00:00
|
|
|
screen.render();
|
|
|
|
}
|
|
|
|
|
|
|
|
void PPU::scanline() {
|
|
|
|
display.width = !hires() ? 256 : 512;
|
|
|
|
display.height = !overscan() ? 225 : 240;
|
2010-09-01 13:22:05 +00:00
|
|
|
if(vcounter() == 0) frame();
|
|
|
|
if(vcounter() == display.height && regs.display_disable == false) oam.address_reset();
|
2010-09-01 13:18:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PPU::frame() {
|
2010-09-01 13:22:05 +00:00
|
|
|
oam.frame();
|
2010-09-01 13:18:10 +00:00
|
|
|
system.frame();
|
|
|
|
}
|
|
|
|
|
|
|
|
void PPU::power() {
|
|
|
|
foreach(n, memory::vram) n = 0;
|
|
|
|
foreach(n, memory::oam) n = 0;
|
|
|
|
foreach(n, memory::cgram) n = 0;
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
void PPU::reset() {
|
|
|
|
create(Enter, system.cpu_frequency());
|
|
|
|
PPUcounter::reset();
|
|
|
|
memset(surface, 0, 512 * 512 * sizeof(uint16));
|
|
|
|
mmio_reset();
|
|
|
|
}
|
|
|
|
|
2010-09-01 13:20:05 +00:00
|
|
|
PPU::PPU() :
|
|
|
|
cache(*this),
|
|
|
|
bg1(*this, Background::ID::BG1),
|
|
|
|
bg2(*this, Background::ID::BG2),
|
|
|
|
bg3(*this, Background::ID::BG3),
|
|
|
|
bg4(*this, Background::ID::BG4),
|
|
|
|
oam(*this),
|
|
|
|
screen(*this) {
|
2010-09-01 13:18:10 +00:00
|
|
|
surface = new uint16[512 * 512];
|
|
|
|
output = surface + 16 * 512;
|
|
|
|
}
|
|
|
|
|
|
|
|
PPU::~PPU() {
|
|
|
|
delete[] surface;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|