diff --git a/ares/gba/ppu/background.cpp b/ares/gba/ppu/background.cpp index 1aa6cb3b5..52a3461d5 100644 --- a/ares/gba/ppu/background.cpp +++ b/ares/gba/ppu/background.cpp @@ -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; } diff --git a/ares/gba/ppu/io.cpp b/ares/gba/ppu/io.cpp index 7d0516b6c..9b43a84b2 100644 --- a/ares/gba/ppu/io.cpp +++ b/ares/gba/ppu/io.cpp @@ -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 @@ -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); diff --git a/ares/gba/ppu/object.cpp b/ares/gba/ppu/object.cpp index 4f57042c1..bdf0160c8 100644 --- a/ares/gba/ppu/object.cpp +++ b/ares/gba/ppu/object.cpp @@ -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; @@ -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; } diff --git a/ares/gba/ppu/ppu.cpp b/ares/gba/ppu/ppu.cpp index 4ef2c8630..412e121ca 100644 --- a/ares/gba/ppu/ppu.cpp +++ b/ares/gba/ppu/ppu.cpp @@ -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 { @@ -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); diff --git a/ares/gba/ppu/ppu.hpp b/ares/gba/ppu/ppu.hpp index 9739d381e..50ec5ea6c 100644 --- a/ares/gba/ppu/ppu.hpp +++ b/ares/gba/ppu/ppu.hpp @@ -70,7 +70,7 @@ struct PPU : Thread, IO { struct IO { n1 gameBoyColorMode; - n1 forceBlank; + n1 forceBlank[4]; n1 greenSwap; n1 vblank; @@ -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; @@ -115,7 +116,7 @@ struct PPU : Thread, IO { static n5 mosaicWidth; static n5 mosaicHeight; - n1 enable; + n1 enable[4]; n2 priority; n2 characterBase; @@ -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; @@ -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 diff --git a/ares/gba/ppu/serialization.cpp b/ares/gba/ppu/serialization.cpp index 8f7b94d88..8551eb55d 100644 --- a/ares/gba/ppu/serialization.cpp +++ b/ares/gba/ppu/serialization.cpp @@ -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); @@ -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); @@ -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); diff --git a/ares/gba/system/serialization.cpp b/ares/gba/system/serialization.cpp index 6662a59c0..4f1af4042 100644 --- a/ares/gba/system/serialization.cpp +++ b/ares/gba/system/serialization.cpp @@ -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);