mirror of https://github.com/bsnes-emu/bsnes.git
236 lines
4.3 KiB
C++
236 lines
4.3 KiB
C++
#include <sfc/sfc.hpp>
|
|
|
|
namespace SuperFamicom {
|
|
|
|
PPU ppu;
|
|
|
|
#include "memory.cpp"
|
|
#include "mmio.cpp"
|
|
#include "background/background.cpp"
|
|
#include "object/object.cpp"
|
|
#include "window/window.cpp"
|
|
#include "screen/screen.cpp"
|
|
#include "serialization.cpp"
|
|
|
|
PPU::PPU() :
|
|
bg1(Background::ID::BG1),
|
|
bg2(Background::ID::BG2),
|
|
bg3(Background::ID::BG3),
|
|
bg4(Background::ID::BG4) {
|
|
ppu1.version = 1; //allowed values: 1
|
|
ppu2.version = 3; //allowed values: 1, 2, 3
|
|
|
|
output = new uint32[512 * 512];
|
|
output += 16 * 512; //overscan offset
|
|
}
|
|
|
|
PPU::~PPU() {
|
|
output -= 16 * 512;
|
|
delete[] output;
|
|
}
|
|
|
|
auto PPU::step(uint clocks) -> void {
|
|
clock += clocks;
|
|
}
|
|
|
|
auto PPU::synchronizeCPU() -> void {
|
|
if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
|
|
}
|
|
|
|
auto PPU::Enter() -> void {
|
|
while(true) scheduler.synchronize(), ppu.main();
|
|
}
|
|
|
|
auto PPU::main() -> void {
|
|
scanline();
|
|
addClocks(28);
|
|
bg1.begin();
|
|
bg2.begin();
|
|
bg3.begin();
|
|
bg4.begin();
|
|
|
|
if(vcounter() <= 239) {
|
|
for(int pixel = -7; pixel <= 255; pixel++) {
|
|
bg1.run(1);
|
|
bg2.run(1);
|
|
bg3.run(1);
|
|
bg4.run(1);
|
|
addClocks(2);
|
|
|
|
bg1.run(0);
|
|
bg2.run(0);
|
|
bg3.run(0);
|
|
bg4.run(0);
|
|
if(pixel >= 0) {
|
|
obj.run();
|
|
window.run();
|
|
screen.run();
|
|
}
|
|
addClocks(2);
|
|
}
|
|
|
|
addClocks(14);
|
|
obj.tilefetch();
|
|
} else {
|
|
addClocks(1052 + 14 + 136);
|
|
}
|
|
|
|
addClocks(lineclocks() - 28 - 1052 - 14 - 136);
|
|
}
|
|
|
|
auto PPU::addClocks(uint clocks) -> void {
|
|
clocks >>= 1;
|
|
while(clocks--) {
|
|
tick(2);
|
|
step(2);
|
|
synchronizeCPU();
|
|
}
|
|
}
|
|
|
|
auto PPU::power() -> void {
|
|
for(auto& n : vram) n = random(0x00);
|
|
for(auto& n : oam) n = random(0x00);
|
|
for(auto& n : cgram) n = random(0x00);
|
|
}
|
|
|
|
auto PPU::reset() -> void {
|
|
create(Enter, system.cpuFrequency());
|
|
PPUcounter::reset();
|
|
memory::fill(output, 512 * 480 * sizeof(uint32));
|
|
|
|
function<auto (uint24, uint8) -> uint8> reader{&PPU::read, this};
|
|
function<auto (uint24, uint8) -> void> writer{&PPU::write, this};
|
|
bus.map(reader, writer, "00-3f,80-bf:2100-213f");
|
|
|
|
ppu1.mdr = random(0xff);
|
|
ppu2.mdr = random(0xff);
|
|
|
|
latch.vram = random(0x0000);
|
|
latch.oam = random(0x00);
|
|
latch.cgram = random(0x00);
|
|
latch.bgofs = random(0x00);
|
|
latch.mode7 = random(0x00);
|
|
latch.counters = false;
|
|
latch.hcounter = 0;
|
|
latch.vcounter = 0;
|
|
|
|
latch.oamAddress = 0x0000;
|
|
latch.cgramAddress = 0x00;
|
|
|
|
//$2100 INIDISP
|
|
r.displayDisable = true;
|
|
r.displayBrightness = 0;
|
|
|
|
//$2102 OAMADDL
|
|
//$2103 OAMADDH
|
|
r.oamBaseAddress = random(0x0000);
|
|
r.oamAddress = random(0x0000);
|
|
r.oamPriority = random(false);
|
|
|
|
//$2105 BGMODE
|
|
r.bgPriority = false;
|
|
r.bgMode = 0;
|
|
|
|
//$210d BG1HOFS
|
|
r.hoffsetMode7 = random(0x0000);
|
|
|
|
//$210e BG1VOFS
|
|
r.voffsetMode7 = random(0x0000);
|
|
|
|
//$2115 VMAIN
|
|
r.vramIncrementMode = random(1);
|
|
r.vramMapping = random(0);
|
|
r.vramIncrementSize = 1;
|
|
|
|
//$2116 VMADDL
|
|
//$2117 VMADDH
|
|
r.vramAddress = random(0x0000);
|
|
|
|
//$211a M7SEL
|
|
r.repeatMode7 = random(0);
|
|
r.vflipMode7 = random(false);
|
|
r.hflipMode7 = random(false);
|
|
|
|
//$211b M7A
|
|
r.m7a = random(0x0000);
|
|
|
|
//$211c M7B
|
|
r.m7b = random(0x0000);
|
|
|
|
//$211d M7C
|
|
r.m7c = random(0x0000);
|
|
|
|
//$211e M7D
|
|
r.m7d = random(0x0000);
|
|
|
|
//$211f M7X
|
|
r.m7x = random(0x0000);
|
|
|
|
//$2120 M7Y
|
|
r.m7y = random(0x0000);
|
|
|
|
//$2121 CGADD
|
|
r.cgramAddress = random(0x0000);
|
|
|
|
//$2133 SETINI
|
|
r.extbg = random(false);
|
|
r.pseudoHires = random(false);
|
|
r.overscan = false;
|
|
r.interlace = false;
|
|
|
|
//$213c OPHCT
|
|
r.hcounter = 0;
|
|
|
|
//$213d OPVCT
|
|
r.vcounter = 0;
|
|
|
|
bg1.reset();
|
|
bg2.reset();
|
|
bg3.reset();
|
|
bg4.reset();
|
|
obj.reset();
|
|
window.reset();
|
|
screen.reset();
|
|
|
|
frame();
|
|
}
|
|
|
|
auto PPU::scanline() -> void {
|
|
if(vcounter() == 0) {
|
|
frame();
|
|
bg1.frame();
|
|
bg2.frame();
|
|
bg3.frame();
|
|
bg4.frame();
|
|
}
|
|
|
|
bg1.scanline();
|
|
bg2.scanline();
|
|
bg3.scanline();
|
|
bg4.scanline();
|
|
obj.scanline();
|
|
window.scanline();
|
|
screen.scanline();
|
|
|
|
if(vcounter() == 241) {
|
|
scheduler.exit(Scheduler::Event::Frame);
|
|
}
|
|
}
|
|
|
|
auto PPU::frame() -> void {
|
|
obj.frame();
|
|
display.interlace = r.interlace;
|
|
display.overscan = r.overscan;
|
|
}
|
|
|
|
auto PPU::refresh() -> void {
|
|
auto output = this->output;
|
|
if(!overscan()) output -= 14 * 512;
|
|
auto pitch = 512;
|
|
auto width = 512;
|
|
auto height = 480;
|
|
Emulator::video.refresh(output, pitch * sizeof(uint32), width, height);
|
|
}
|
|
|
|
}
|