2012-03-19 11:19:53 +00:00
|
|
|
#include <gba/gba.hpp>
|
|
|
|
|
2012-03-21 11:08:16 +00:00
|
|
|
//pixel: 4 cycles
|
|
|
|
|
|
|
|
//hdraw: 240 pixels ( 960 cycles)
|
|
|
|
//hblank: 68 pixels ( 272 cycles)
|
|
|
|
//scanline: 308 pixels (1232 cycles)
|
|
|
|
|
|
|
|
//vdraw: 160 scanlines (197120 cycles)
|
|
|
|
//vblank: 68 scanlines ( 83776 cycles)
|
2012-03-29 11:58:10 +00:00
|
|
|
//frame: 228 scanlines (280896 cycles)
|
2012-03-21 11:08:16 +00:00
|
|
|
|
2012-03-19 11:19:53 +00:00
|
|
|
namespace GBA {
|
|
|
|
|
2012-03-31 08:14:31 +00:00
|
|
|
#include "registers.cpp"
|
2012-04-03 23:50:40 +00:00
|
|
|
#include "background.cpp"
|
2012-04-03 00:47:28 +00:00
|
|
|
#include "object.cpp"
|
|
|
|
#include "screen.cpp"
|
2012-03-31 08:14:31 +00:00
|
|
|
#include "mmio.cpp"
|
2012-04-09 06:41:27 +00:00
|
|
|
#include "memory.cpp"
|
2012-03-19 11:19:53 +00:00
|
|
|
PPU ppu;
|
|
|
|
|
|
|
|
void PPU::Enter() { ppu.enter(); }
|
|
|
|
|
|
|
|
void PPU::enter() {
|
|
|
|
while(true) {
|
2012-03-29 11:58:10 +00:00
|
|
|
scanline();
|
2012-03-19 11:19:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PPU::step(unsigned clocks) {
|
|
|
|
clock += clocks;
|
|
|
|
if(clock >= 0) co_switch(cpu.thread);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PPU::power() {
|
|
|
|
create(PPU::Enter, 16777216);
|
|
|
|
|
2012-04-09 06:41:27 +00:00
|
|
|
//for(unsigned n = 0; n < vram.size; n++) vram.data[n] = 0;
|
2012-03-31 08:17:36 +00:00
|
|
|
for(unsigned n = 0; n < 240 * 160; n++) output[n] = 0;
|
2012-03-29 11:58:10 +00:00
|
|
|
|
2012-04-09 06:41:27 +00:00
|
|
|
for(unsigned n = 0; n < 1024; n += 2) pram_write(n, Half, 0x0000);
|
|
|
|
for(unsigned n = 0; n < 1024; n += 2) oam_write(n, Half, 0x0000);
|
2012-04-09 06:19:32 +00:00
|
|
|
|
2012-03-31 08:14:31 +00:00
|
|
|
regs.control = 0;
|
2012-03-31 08:17:36 +00:00
|
|
|
regs.greenswap = 0;
|
|
|
|
regs.status = 0;
|
|
|
|
regs.vcounter = 0;
|
|
|
|
for(auto &bg : regs.bg) {
|
|
|
|
bg.control = 0;
|
|
|
|
bg.hoffset = 0;
|
|
|
|
bg.voffset = 0;
|
|
|
|
bg.pa = 0;
|
|
|
|
bg.pb = 0;
|
|
|
|
bg.pc = 0;
|
|
|
|
bg.pd = 0;
|
|
|
|
bg.x = 0;
|
|
|
|
bg.y = 0;
|
2012-04-07 08:17:49 +00:00
|
|
|
bg.lx = 0;
|
|
|
|
bg.ly = 0;
|
2012-03-31 08:17:36 +00:00
|
|
|
}
|
|
|
|
for(auto &w : regs.window) {
|
|
|
|
w.x1 = 0;
|
|
|
|
w.x2 = 0;
|
|
|
|
w.y1 = 0;
|
|
|
|
w.y2 = 0;
|
|
|
|
w.in = 0;
|
|
|
|
w.out = 0;
|
|
|
|
}
|
|
|
|
regs.windowobj.in = 0;
|
|
|
|
regs.mosaic.bghsize = 0;
|
|
|
|
regs.mosaic.bgvsize = 0;
|
|
|
|
regs.mosaic.objhsize = 0;
|
|
|
|
regs.mosaic.objvsize = 0;
|
|
|
|
regs.blend.control = 0;
|
|
|
|
regs.blend.eva = 0;
|
|
|
|
regs.blend.evb = 0;
|
|
|
|
regs.blend.evy = 0;
|
2012-03-29 11:58:10 +00:00
|
|
|
|
2012-03-31 08:14:31 +00:00
|
|
|
for(unsigned n = 0x000; n <= 0x055; n++) bus.mmio[n] = this;
|
2012-03-29 11:58:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PPU::scanline() {
|
2012-03-31 08:17:36 +00:00
|
|
|
regs.status.vblank = regs.vcounter >= 160 && regs.vcounter <= 226;
|
|
|
|
regs.status.vcoincidence = regs.vcounter == regs.status.vcompare;
|
|
|
|
|
|
|
|
if(regs.vcounter == 0) {
|
|
|
|
frame();
|
2012-04-07 08:17:49 +00:00
|
|
|
|
|
|
|
regs.bg[2].lx = regs.bg[2].x;
|
|
|
|
regs.bg[2].ly = regs.bg[2].y;
|
|
|
|
|
|
|
|
regs.bg[3].lx = regs.bg[3].x;
|
|
|
|
regs.bg[3].ly = regs.bg[3].y;
|
2012-03-31 08:17:36 +00:00
|
|
|
}
|
2012-03-29 11:58:10 +00:00
|
|
|
|
2012-03-31 08:17:36 +00:00
|
|
|
if(regs.vcounter == 160) {
|
2012-04-01 01:41:15 +00:00
|
|
|
if(regs.status.irqvblank) cpu.regs.irq.flag.vblank = 1;
|
2012-04-03 23:50:40 +00:00
|
|
|
cpu.pending.dma.vblank = true;
|
2012-03-29 11:58:10 +00:00
|
|
|
}
|
|
|
|
|
2012-03-31 08:17:36 +00:00
|
|
|
if(regs.status.irqvcoincidence) {
|
2012-04-01 01:41:15 +00:00
|
|
|
if(regs.status.vcoincidence) cpu.regs.irq.flag.vcoincidence = 1;
|
2012-03-29 11:58:10 +00:00
|
|
|
}
|
|
|
|
|
2012-04-03 00:47:28 +00:00
|
|
|
if(regs.vcounter < 160) {
|
2012-04-07 08:17:49 +00:00
|
|
|
for(unsigned x = 0; x < 240; x++) {
|
|
|
|
layer[0][x].exists = false;
|
|
|
|
layer[1][x].exists = false;
|
|
|
|
layer[2][x].exists = false;
|
|
|
|
layer[3][x].exists = false;
|
|
|
|
}
|
|
|
|
|
2012-04-09 06:19:32 +00:00
|
|
|
if(regs.control.forceblank) {
|
|
|
|
render_forceblank();
|
|
|
|
} else {
|
|
|
|
render_backgrounds();
|
|
|
|
render_objects();
|
|
|
|
render_screen();
|
|
|
|
}
|
2012-04-03 00:47:28 +00:00
|
|
|
}
|
|
|
|
|
2012-04-07 08:17:49 +00:00
|
|
|
step(960);
|
2012-03-31 08:17:36 +00:00
|
|
|
regs.status.hblank = 1;
|
2012-04-01 01:41:15 +00:00
|
|
|
if(regs.status.irqhblank) cpu.regs.irq.flag.hblank = 1;
|
2012-04-09 06:19:32 +00:00
|
|
|
if(regs.vcounter < 160) cpu.pending.dma.hblank = true;
|
2012-03-31 08:17:36 +00:00
|
|
|
|
2012-04-07 08:17:49 +00:00
|
|
|
step(240);
|
2012-03-31 08:17:36 +00:00
|
|
|
regs.status.hblank = 0;
|
2012-04-07 08:17:49 +00:00
|
|
|
if(regs.vcounter < 160) cpu.pending.dma.hdma = true;
|
2012-03-31 08:17:36 +00:00
|
|
|
|
2012-04-07 08:17:49 +00:00
|
|
|
step(32);
|
2012-03-31 08:17:36 +00:00
|
|
|
if(++regs.vcounter == 228) regs.vcounter = 0;
|
2012-03-19 11:19:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PPU::frame() {
|
|
|
|
interface->videoRefresh(output);
|
|
|
|
scheduler.exit(Scheduler::ExitReason::FrameEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
PPU::PPU() {
|
2012-03-31 08:17:36 +00:00
|
|
|
output = new uint16[240 * 160];
|
|
|
|
}
|
|
|
|
|
|
|
|
PPU::~PPU() {
|
|
|
|
delete[] output;
|
2012-03-19 11:19:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|