Skip to content

Commit

Permalink
gba: add latches to DISPCNT background enable, object enable, and for…
Browse files Browse the repository at this point in the history
…ce blank bits (#1643)

Clearing the force blank bit or setting the background/object enable
bits in DISPCNT should only take effect after 3 scanlines.
  • Loading branch information
png183 authored Sep 17, 2024
1 parent b5a8edc commit 0b46609
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 33 deletions.
8 changes: 7 additions & 1 deletion ares/gba/ppu/background.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@ n1 PPU::Background::IO::frame;
n5 PPU::Background::IO::mosaicWidth;
n5 PPU::Background::IO::mosaicHeight;

auto PPU::Background::setEnable(n1 status) -> void {
io.enable[3] = status;
for(auto& flag : io.enable) flag &= status;
}

auto PPU::Background::scanline(u32 y) -> void {
memory::move(io.enable, io.enable + 1, sizeof(io.enable) - 1);
mosaicOffset = 0;
}

auto PPU::Background::run(u32 x, u32 y) -> void {
output = {};
if(ppu.blank() || !io.enable) {
if(ppu.blank() || !io.enable[0]) {
mosaic = {};
return;
}
Expand Down
31 changes: 16 additions & 15 deletions ares/gba/ppu/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ auto PPU::readIO(n32 address) -> n8 {
| Background::IO::frame << 4
| objects.io.hblank << 5
| objects.io.mapping << 6
| io.forceBlank << 7
| io.forceBlank[3] << 7
);
case 0x0400'0001: return (
bg0.io.enable << 0
| bg1.io.enable << 1
| bg2.io.enable << 2
| bg3.io.enable << 3
| objects.io.enable << 4
| window0.io.enable << 5
| window1.io.enable << 6
| window2.io.enable << 7
bg0.io.enable[3] << 0
| bg1.io.enable[3] << 1
| bg2.io.enable[3] << 2
| bg3.io.enable[3] << 3
| objects.io.enable[3] << 4
| window0.io.enable << 5
| window1.io.enable << 6
| window2.io.enable << 7
);

//GRSWP
Expand Down Expand Up @@ -112,14 +112,15 @@ auto PPU::writeIO(n32 address, n8 data) -> void {
Background::IO::frame = data.bit(4);
objects.io.hblank = data.bit(5);
objects.io.mapping = data.bit(6);
io.forceBlank = data.bit(7);
io.forceBlank[3] = data.bit(7);
for(auto& flag : io.forceBlank) flag |= data.bit(7);
return;
case 0x0400'0001:
bg0.io.enable = data.bit(0);
bg1.io.enable = data.bit(1);
bg2.io.enable = data.bit(2);
bg3.io.enable = data.bit(3);
objects.io.enable = data.bit(4);
bg0.setEnable(data.bit(0));
bg1.setEnable(data.bit(1));
bg2.setEnable(data.bit(2));
bg3.setEnable(data.bit(3));
objects.setEnable(data.bit(4));
window0.io.enable = data.bit(5);
window1.io.enable = data.bit(6);
window2.io.enable = data.bit(7);
Expand Down
12 changes: 10 additions & 2 deletions ares/gba/ppu/object.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
auto PPU::Objects::setEnable(n1 status) -> void {
io.enable[3] = status;
for(auto& flag : io.enable) flag &= status;
}

auto PPU::Objects::scanline(u32 y) -> void {
memory::move(io.enable, io.enable + 1, sizeof(io.enable) - 1);
if(y >= 160) return;

mosaicOffset = 0;
for(auto& pixel : buffer) pixel = {};
if(ppu.blank() || !io.enable) return;
if(ppu.blank() || !io.enable[0]) return;

for(auto& object : ppu.object) {
n8 py = y - object.y;
Expand Down Expand Up @@ -74,7 +82,7 @@ auto PPU::Objects::scanline(u32 y) -> void {

auto PPU::Objects::run(u32 x, u32 y) -> void {
output = {};
if(ppu.blank() || !io.enable) {
if(ppu.blank() || !io.enable[0]) {
mosaic = {};
return;
}
Expand Down
17 changes: 9 additions & 8 deletions ares/gba/ppu/ppu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ auto PPU::unload() -> void {
}

inline auto PPU::blank() -> bool {
return io.forceBlank || cpu.stopped();
return io.forceBlank[0] || cpu.stopped();
}

auto PPU::step(u32 clocks) -> void {
Expand Down Expand Up @@ -108,13 +108,14 @@ auto PPU::main() -> void {

step(46);

if(io.vcounter < 160) {
u32 y = io.vcounter;
bg0.scanline(y);
bg1.scanline(y);
bg2.scanline(y);
bg3.scanline(y);
objects.scanline(y);
u32 y = io.vcounter;
memory::move(io.forceBlank, io.forceBlank + 1, sizeof(io.forceBlank) - 1);
bg0.scanline(y);
bg1.scanline(y);
bg2.scanline(y);
bg3.scanline(y);
objects.scanline(y);
if(y < 160) {
auto line = screen->pixels().data() + y * 240;
for(u32 x : range(240)) {
bg0.run(x, y);
Expand Down
8 changes: 5 additions & 3 deletions ares/gba/ppu/ppu.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ struct PPU : Thread, IO {

struct IO {
n1 gameBoyColorMode;
n1 forceBlank;
n1 forceBlank[4];
n1 greenSwap;

n1 vblank;
Expand All @@ -97,6 +97,7 @@ struct PPU : Thread, IO {

struct Background {
//background.cpp
auto setEnable(n1 status) -> void;
auto scanline(u32 y) -> void;
auto run(u32 x, u32 y) -> void;
auto linear(u32 x, u32 y) -> void;
Expand All @@ -115,7 +116,7 @@ struct PPU : Thread, IO {
static n5 mosaicWidth;
static n5 mosaicHeight;

n1 enable;
n1 enable[4];

n2 priority;
n2 characterBase;
Expand Down Expand Up @@ -162,6 +163,7 @@ struct PPU : Thread, IO {

struct Objects {
//object.cpp
auto setEnable(n1 status) -> void;
auto scanline(u32 y) -> void;
auto run(u32 x, u32 y) -> void;
auto power() -> void;
Expand All @@ -170,7 +172,7 @@ struct PPU : Thread, IO {
auto serialize(serializer&) -> void;

struct IO {
n1 enable;
n1 enable[4];

n1 hblank; //1 = allow access to OAM during Hblank
n1 mapping; //0 = two-dimensional, 1 = one-dimensional
Expand Down
6 changes: 3 additions & 3 deletions ares/gba/ppu/serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ auto PPU::serialize(serializer& s) -> void {
s(pram);

s(io.gameBoyColorMode);
s(io.forceBlank);
for(auto& flag : io.forceBlank) s(flag);
s(io.greenSwap);
s(io.vblank);
s(io.hblank);
Expand Down Expand Up @@ -39,7 +39,7 @@ auto PPU::serialize(serializer& s) -> void {
auto PPU::Background::serialize(serializer& s) -> void {
s(id);

s(io.enable);
for(auto& flag : io.enable) s(flag);
s(io.priority);
s(io.characterBase);
s(io.unused);
Expand Down Expand Up @@ -67,7 +67,7 @@ auto PPU::Background::serialize(serializer& s) -> void {
}

auto PPU::Objects::serialize(serializer& s) -> void {
s(io.enable);
for(auto& flag : io.enable) s(flag);
s(io.hblank);
s(io.mapping);
s(io.mosaicWidth);
Expand Down
2 changes: 1 addition & 1 deletion ares/gba/system/serialization.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
static const string SerializerVersion = "v140";
static const string SerializerVersion = "v140.1";

auto System::serialize(bool synchronize) -> serializer {
if(synchronize) scheduler.enter(Scheduler::Mode::Synchronize);
Expand Down

0 comments on commit 0b46609

Please sign in to comment.