-
Notifications
You must be signed in to change notification settings - Fork 128
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
gba: cycle-based bitmap and affine backgrounds (#1714)
The pixel accuracy setting will now emulate the sub-pixel timing behaviours for bitmap and affine backgrounds described in [fleroviux's PPU docs](https://github.com/nba-emu/hw-docs/blob/main/src/ppu/background.md). This PR also splits the PPU into two separate libco threads: one for rendering and one for raising IRQs and starting DMAs. This allows the CPU and PPU to be run more asynchronously, which helps mitigate the performance cost of finer-grained PPU emulation.
- Loading branch information
Showing
17 changed files
with
399 additions
and
190 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
#include <gba/gba.hpp> | ||
|
||
//The only PPU state the CPU needs on every cycle is raised IRQs and DMAs, | ||
//which occur independently of the render process. | ||
//Display exists to put these events on a separate thread, | ||
//so the CPU and PPU can run out-of-order. | ||
|
||
//hdraw: 1006 cycles | ||
//hblank: 226 cycles | ||
//scanline: 1232 cycles | ||
|
||
//vdraw: 160 scanlines (197120 cycles) | ||
//vblank: 68 scanlines ( 83776 cycles) | ||
//frame: 228 scanlines (280896 cycles) | ||
|
||
namespace ares::GameBoyAdvance { | ||
|
||
Display display; | ||
#include "io.cpp" | ||
#include "serialization.cpp" | ||
|
||
auto Display::load(Node::Object parent) -> void { | ||
node = parent->append<Node::Object>("Display"); | ||
} | ||
|
||
auto Display::unload() -> void { | ||
node.reset(); | ||
} | ||
|
||
auto Display::step(u32 clocks) -> void { | ||
Thread::step(clocks); | ||
Thread::synchronize(cpu); | ||
} | ||
|
||
auto Display::main() -> void { | ||
cpu.keypad.run(); | ||
|
||
io.vblank = io.vcounter >= 160 && io.vcounter <= 226; | ||
|
||
step(1); | ||
|
||
io.vcoincidence = io.vcounter == io.vcompare; | ||
|
||
if(io.vcounter == 160) { | ||
if(io.irqvblank) cpu.setInterruptFlag(CPU::Interrupt::VBlank); | ||
} | ||
|
||
step(1); | ||
|
||
if(io.irqvcoincidence) { | ||
if(io.vcoincidence) cpu.setInterruptFlag(CPU::Interrupt::VCoincidence); | ||
} | ||
|
||
if(io.vcounter == 160) { | ||
cpu.dmaVblank(); | ||
} | ||
|
||
step(3); | ||
|
||
if(io.vcounter == 162) { | ||
if(videoCapture) cpu.dma[3].enable = 0; | ||
videoCapture = !videoCapture && cpu.dma[3].timingMode == 3 && cpu.dma[3].enable; | ||
} | ||
if(io.vcounter >= 2 && io.vcounter < 162 && videoCapture) cpu.dmaHDMA(); | ||
|
||
step(1002); | ||
|
||
io.hblank = 1; | ||
|
||
step(1); | ||
if(io.irqhblank) cpu.setInterruptFlag(CPU::Interrupt::HBlank); | ||
|
||
step(1); | ||
if(io.vcounter < 160) cpu.dmaHblank(); | ||
|
||
step(223); | ||
io.hblank = 0; | ||
if(++io.vcounter == 228) io.vcounter = 0; | ||
} | ||
|
||
auto Display::power() -> void { | ||
Thread::create(system.frequency(), {&Display::main, this}); | ||
|
||
for(u32 n = 0x004; n <= 0x007; n++) bus.io[n] = this; | ||
|
||
io = {}; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
struct Display : Thread, IO { | ||
Node::Object node; | ||
|
||
auto load(Node::Object) -> void; | ||
auto unload() -> void; | ||
|
||
auto step(u32 clocks) -> void; | ||
auto main() -> void; | ||
|
||
auto power() -> void; | ||
|
||
//io.cpp | ||
auto readIO(n32 address) -> n8; | ||
auto writeIO(n32 address, n8 byte) -> void; | ||
|
||
//serialization.cpp | ||
auto serialize(serializer&) -> void; | ||
|
||
struct IO { | ||
n1 vblank; | ||
n1 hblank; | ||
n1 vcoincidence; | ||
n1 irqvblank; | ||
n1 irqhblank; | ||
n1 irqvcoincidence; | ||
n8 vcompare; | ||
|
||
n16 vcounter; | ||
} io; | ||
|
||
n1 videoCapture = 0; | ||
}; | ||
|
||
extern Display display; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
auto Display::readIO(n32 address) -> n8 { | ||
switch(address) { | ||
|
||
//DISPSTAT | ||
case 0x0400'0004: return ( | ||
io.vblank << 0 | ||
| io.hblank << 1 | ||
| io.vcoincidence << 2 | ||
| io.irqvblank << 3 | ||
| io.irqhblank << 4 | ||
| io.irqvcoincidence << 5 | ||
); | ||
case 0x0400'0005: return ( | ||
io.vcompare | ||
); | ||
|
||
//VCOUNT | ||
case 0x0400'0006: return io.vcounter.byte(0); | ||
case 0x0400'0007: return io.vcounter.byte(1); | ||
|
||
} | ||
|
||
return cpu.openBus.get(Byte, address); | ||
} | ||
|
||
auto Display::writeIO(n32 address, n8 data) -> void { | ||
switch(address) { | ||
|
||
//DISPSTAT | ||
case 0x0400'0004: | ||
io.irqvblank = data.bit(3); | ||
io.irqhblank = data.bit(4); | ||
io.irqvcoincidence = data.bit(5); | ||
return; | ||
case 0x0400'0005: | ||
io.vcompare = data; | ||
return; | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
auto Display::serialize(serializer& s) -> void { | ||
s(io.vblank); | ||
s(io.hblank); | ||
s(io.vcoincidence); | ||
s(io.irqvblank); | ||
s(io.irqhblank); | ||
s(io.irqvcoincidence); | ||
s(io.vcompare); | ||
s(io.vcounter); | ||
|
||
s(videoCapture); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.