Serialize SDD1 PEM
(fixes run-ahead in Star Ocean)
Dot PPU: calculate nameTableIndex and characterIndex from ppu.hcounter()
(fixes scanline glitch in Great Battle IV)
Dot PPU: do not latch BG H/V scroll registers
(fixes Air Strike Patrol raster effects)
(fixes Septentrion glitchy scanline)
This commit is contained in:
byuu 2020-01-16 23:12:37 +09:00
parent 358a3ceed7
commit 52d5b3e2a2
7 changed files with 54 additions and 76 deletions

View File

@ -29,13 +29,13 @@ using namespace nall;
namespace Emulator {
static const string Name = "bsnes";
static const string Version = "114.1";
static const string Version = "114.2";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "https://byuu.org";
//incremented only when serialization format changes
static const string SerializerVersion = "114.1";
static const string SerializerVersion = "114.2";
namespace Constants {
namespace Colorburst {

View File

@ -6,9 +6,9 @@ auto SDD1::serialize(serializer& s) -> void {
s.integer(r4806);
s.integer(r4807);
for(auto n : range(8)) {
s.integer(dma[n].addr);
s.integer(dma[n].size);
for(auto& channel : dma) {
s.integer(channel.addr);
s.integer(channel.size);
}
s.integer(dmaReady);
@ -26,6 +26,7 @@ auto SDD1::Decompressor::serialize(serializer& s) -> void {
bg5.serialize(s);
bg6.serialize(s);
bg7.serialize(s);
pem.serialize(s);
cm.serialize(s);
ol.serialize(s);
}

View File

@ -13,13 +13,6 @@ auto PPU::Background::scanline() -> void {
mosaic.hcounter = ppu.mosaic.size;
mosaic.hoffset = 0;
if(io.mode == Mode::Mode7) return beginMode7();
latch.hoffset = io.hoffset;
latch.voffset = io.voffset;
nameTableIndex = 0;
characterIndex = 0;
renderingIndex = 0;
opt.hoffset = 0;
@ -36,11 +29,13 @@ auto PPU::Background::begin() -> void {
auto PPU::Background::fetchNameTable() -> void {
if(ppu.vcounter() == 0) return;
uint nameTableIndex = ppu.hcounter() >> 5 << hires();
int x = (ppu.hcounter() & ~31) >> 2;
uint hpixel = x << hires();
uint vpixel = ppu.vcounter();
uint hscroll = latch.hoffset;
uint vscroll = latch.voffset;
uint hscroll = io.hoffset;
uint vscroll = io.voffset;
if(mosaic.enable) vpixel -= ppu.mosaic.voffset();
if(hires()) {
@ -131,6 +126,7 @@ auto PPU::Background::fetchNameTable() -> void {
auto PPU::Background::fetchOffset(uint y) -> void {
if(ppu.vcounter() == 0) return;
uint characterIndex = ppu.hcounter() >> 5 << hires();
uint x = characterIndex << 3;
uint hoffset = x + (io.hoffset & ~7);
@ -152,13 +148,13 @@ auto PPU::Background::fetchOffset(uint y) -> void {
uint16 address = io.screenAddress + offset;
if(y == 0) opt.hoffset = ppu.vram[address];
if(y == 8) opt.voffset = ppu.vram[address];
if(y == 0) characterIndex++;
}
auto PPU::Background::fetchCharacter(uint index) -> void {
auto PPU::Background::fetchCharacter(uint index, bool half) -> void {
if(ppu.vcounter() == 0) return;
uint characterIndex = (ppu.hcounter() >> 5 << hires()) + half;
auto& tile = tiles[characterIndex];
uint16 data = ppu.vram[tile.address + (index << 3)];
@ -174,8 +170,6 @@ auto PPU::Background::fetchCharacter(uint index) -> void {
((uint8(data >> 0) * 0x0101010101010101ull & 0x8040201008040201ull) * 0x0102040810204081ull >> 49) & 0x5555
| ((uint8(data >> 8) * 0x0101010101010101ull & 0x8040201008040201ull) * 0x0102040810204081ull >> 48) & 0xaaaa
);
if(index == 0) characterIndex++;
}
auto PPU::Background::run(bool screen) -> void {
@ -230,8 +224,6 @@ auto PPU::Background::power() -> void {
io.hoffset = random();
io.voffset = random();
latch = {};
output.above = {};
output.below = {};

View File

@ -9,13 +9,12 @@ struct Background {
auto begin() -> void;
auto fetchNameTable() -> void;
auto fetchOffset(uint y) -> void;
auto fetchCharacter(uint index) -> void;
auto fetchCharacter(uint index, bool half = 0) -> void;
auto run(bool screen) -> void;
auto power() -> void;
//mode7.cpp
alwaysinline auto clip(int n) -> int;
auto beginMode7() -> void;
auto runMode7() -> void;
auto serialize(serializer&) -> void;
@ -44,11 +43,6 @@ struct Background {
uint16 voffset;
} io;
struct Latch {
uint16 hoffset;
uint16 voffset;
} latch;
struct Pixel {
uint8 priority; //0 = none (transparent)
uint8 palette;
@ -84,8 +78,8 @@ struct Background {
uint16 data[4];
} tiles[66];
uint7 nameTableIndex;
uint7 characterIndex;
uint7 nameTableIndex2;
uint7 characterIndex2;
uint7 renderingIndex;
uint3 pixelCounter;

View File

@ -95,60 +95,60 @@ auto PPU::cycleBackgroundFetch() -> void {
if constexpr(Cycle == 1) bg2.fetchNameTable();
if constexpr(Cycle == 2) bg1.fetchNameTable();
if constexpr(Cycle == 3) bg3.fetchCharacter(0);
if constexpr(Cycle == 4) bg2.fetchCharacter(1);
if constexpr(Cycle == 5) bg2.fetchCharacter(0);
if constexpr(Cycle == 6) bg1.fetchCharacter(1);
if constexpr(Cycle == 7) bg1.fetchCharacter(0);
if constexpr(Cycle == 4) bg2.fetchCharacter(0);
if constexpr(Cycle == 5) bg2.fetchCharacter(1);
if constexpr(Cycle == 6) bg1.fetchCharacter(0);
if constexpr(Cycle == 7) bg1.fetchCharacter(1);
break;
case 2:
if constexpr(Cycle == 0) bg2.fetchNameTable();
if constexpr(Cycle == 1) bg1.fetchNameTable();
if constexpr(Cycle == 2) bg3.fetchOffset(8);
if constexpr(Cycle == 3) bg3.fetchOffset(0);
if constexpr(Cycle == 4) bg2.fetchCharacter(1);
if constexpr(Cycle == 5) bg2.fetchCharacter(0);
if constexpr(Cycle == 6) bg1.fetchCharacter(1);
if constexpr(Cycle == 7) bg1.fetchCharacter(0);
if constexpr(Cycle == 2) bg3.fetchOffset(0);
if constexpr(Cycle == 3) bg3.fetchOffset(8);
if constexpr(Cycle == 4) bg2.fetchCharacter(0);
if constexpr(Cycle == 5) bg2.fetchCharacter(1);
if constexpr(Cycle == 6) bg1.fetchCharacter(0);
if constexpr(Cycle == 7) bg1.fetchCharacter(1);
break;
case 3:
if constexpr(Cycle == 0) bg2.fetchNameTable();
if constexpr(Cycle == 1) bg1.fetchNameTable();
if constexpr(Cycle == 2) bg2.fetchCharacter(1);
if constexpr(Cycle == 3) bg2.fetchCharacter(0);
if constexpr(Cycle == 4) bg1.fetchCharacter(3);
if constexpr(Cycle == 5) bg1.fetchCharacter(2);
if constexpr(Cycle == 6) bg1.fetchCharacter(1);
if constexpr(Cycle == 7) bg1.fetchCharacter(0);
if constexpr(Cycle == 2) bg2.fetchCharacter(0);
if constexpr(Cycle == 3) bg2.fetchCharacter(1);
if constexpr(Cycle == 4) bg1.fetchCharacter(0);
if constexpr(Cycle == 5) bg1.fetchCharacter(1);
if constexpr(Cycle == 6) bg1.fetchCharacter(2);
if constexpr(Cycle == 7) bg1.fetchCharacter(3);
break;
case 4:
if constexpr(Cycle == 0) bg2.fetchNameTable();
if constexpr(Cycle == 1) bg1.fetchNameTable();
if constexpr(Cycle == 2) bg3.fetchOffset(0);
if constexpr(Cycle == 3) bg2.fetchCharacter(0);
if constexpr(Cycle == 4) bg1.fetchCharacter(3);
if constexpr(Cycle == 5) bg1.fetchCharacter(2);
if constexpr(Cycle == 6) bg1.fetchCharacter(1);
if constexpr(Cycle == 7) bg1.fetchCharacter(0);
if constexpr(Cycle == 4) bg1.fetchCharacter(0);
if constexpr(Cycle == 5) bg1.fetchCharacter(1);
if constexpr(Cycle == 6) bg1.fetchCharacter(2);
if constexpr(Cycle == 7) bg1.fetchCharacter(3);
break;
case 5:
if constexpr(Cycle == 0) bg2.fetchNameTable();
if constexpr(Cycle == 1) bg1.fetchNameTable();
if constexpr(Cycle == 2) bg2.fetchCharacter(0);
if constexpr(Cycle == 3) bg2.fetchCharacter(0);
if constexpr(Cycle == 4) bg1.fetchCharacter(1);
if constexpr(Cycle == 5) bg1.fetchCharacter(0);
if constexpr(Cycle == 6) bg1.fetchCharacter(1);
if constexpr(Cycle == 7) bg1.fetchCharacter(0);
if constexpr(Cycle == 2) bg2.fetchCharacter(0, 0);
if constexpr(Cycle == 3) bg2.fetchCharacter(0, 1);
if constexpr(Cycle == 4) bg1.fetchCharacter(0, 0);
if constexpr(Cycle == 5) bg1.fetchCharacter(1, 0);
if constexpr(Cycle == 6) bg1.fetchCharacter(0, 1);
if constexpr(Cycle == 7) bg1.fetchCharacter(1, 1);
break;
case 6:
if constexpr(Cycle == 0) bg2.fetchNameTable();
if constexpr(Cycle == 1) bg1.fetchNameTable();
if constexpr(Cycle == 2) bg3.fetchOffset(8);
if constexpr(Cycle == 3) bg3.fetchOffset(0);
if constexpr(Cycle == 4) bg1.fetchCharacter(1);
if constexpr(Cycle == 5) bg1.fetchCharacter(0);
if constexpr(Cycle == 6) bg1.fetchCharacter(1);
if constexpr(Cycle == 7) bg1.fetchCharacter(0);
if constexpr(Cycle == 2) bg3.fetchOffset(0);
if constexpr(Cycle == 3) bg3.fetchOffset(8);
if constexpr(Cycle == 4) bg1.fetchCharacter(0, 0);
if constexpr(Cycle == 5) bg1.fetchCharacter(1, 0);
if constexpr(Cycle == 6) bg1.fetchCharacter(0, 1);
if constexpr(Cycle == 7) bg1.fetchCharacter(1, 1);
break;
case 7:
//handled separately by mode7.cpp

View File

@ -3,12 +3,6 @@ auto PPU::Background::clip(int n) -> int {
return n & 0x2000 ? (n | ~1023) : (n & 1023);
}
//H = 0
auto PPU::Background::beginMode7() -> void {
latch.hoffset = ppu.io.hoffsetMode7;
latch.voffset = ppu.io.voffsetMode7;
}
auto PPU::Background::runMode7() -> void {
int a = (int16)ppu.io.m7a;
int b = (int16)ppu.io.m7b;
@ -17,14 +11,16 @@ auto PPU::Background::runMode7() -> void {
int hcenter = (int13)ppu.io.m7x;
int vcenter = (int13)ppu.io.m7y;
int hoffset = (int13)latch.hoffset;
int voffset = (int13)latch.voffset;
int hoffset = (int13)ppu.io.hoffsetMode7;
int voffset = (int13)ppu.io.voffsetMode7;
uint x = mosaic.hoffset;
uint y = ppu.vcounter();
if(ppu.bg1.mosaic.enable) y -= ppu.mosaic.voffset(); //BG2 vertical mosaic uses BG1 mosaic enable
if(--mosaic.hcounter == 0) {
if(!mosaic.enable) {
mosaic.hoffset += 1;
} else if(--mosaic.hcounter == 0) {
mosaic.hcounter = ppu.mosaic.size;
mosaic.hoffset += ppu.mosaic.size;
}

View File

@ -100,9 +100,6 @@ auto PPU::Background::serialize(serializer& s) -> void {
s.integer(io.hoffset);
s.integer(io.voffset);
s.integer(latch.hoffset);
s.integer(latch.voffset);
s.integer(output.above.priority);
s.integer(output.above.palette);
s.integer(output.above.paletteGroup);
@ -133,8 +130,6 @@ auto PPU::Background::serialize(serializer& s) -> void {
s.array(tile.data);
}
s.integer(nameTableIndex);
s.integer(characterIndex);
s.integer(renderingIndex);
s.integer(pixelCounter);
}