[SOLVED] Donkey Kong Title Screen Filled With Zeros

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
hypnotron
Posts: 8
Joined: Fri Apr 17, 2020 7:21 pm

[SOLVED] Donkey Kong Title Screen Filled With Zeros

Post by hypnotron » Mon Jun 08, 2020 8:33 am

I'm working on my emulator's PPU and most simple NROM games are now playable; however, there's always some form of jank inside the nametables on boot. Take a look at Donkey Kong, for example.
On boot:
boot.png
boot.png (9.19 KiB) Viewed 1131 times
After reset:
after-reset.png
after-reset.png (8.6 KiB) Viewed 1131 times
I suspect this is related to my PPUADDR implementation or vblank timing, but I honestly have no idea what the source of this bug is. Nessdl's source code is here (see 2C02.hpp). Thanks in advance to anyone who can point me in the right direction.
Last edited by hypnotron on Tue Jun 09, 2020 9:55 am, edited 1 time in total.

User avatar
Memblers
Site Admin
Posts: 3880
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Re: Donkey Kong Title Screen Filled With Zeros

Post by Memblers » Mon Jun 08, 2020 9:01 am

Similar symptoms were seen in this thread:
http://forums.nesdev.com/viewtopic.php?f=3&t=19926

hypnotron
Posts: 8
Joined: Fri Apr 17, 2020 7:21 pm

Re: Donkey Kong Title Screen Filled With Zeros

Post by hypnotron » Mon Jun 08, 2020 9:36 am

Memblers wrote:
Mon Jun 08, 2020 9:01 am
Similar symptoms were seen in this thread:
http://forums.nesdev.com/viewtopic.php?f=3&t=19926
I checked my v/t register updates against the PPU Scrolling wiki page and there don't appear to be any mistakes, although that thread did help me solve another unrelated PPU bug earlier.

(address: v)
(startAddress: t)
After BG shift register reload:

Code: Select all

void incrementX() {
    if ((address++ & 0x001F) == 0x001F) {
        --address &= 0xFFE0;
        address ^= 0x0400;
    }
}

void incrementY() {
    if ((address += 0x1000) & 0x8000) {
        address -= 0x8000; 
        u8_fast coarseY = (address & 0x03E0) >> 5;
        if (coarseY == 29) {
            address ^= 0x0800;
        }
        coarseY = coarseY == 29 || coarseY == 31 
              ? 0
              : coarseY + 1;
        address &= 0xFC1F;
        address |= coarseY << 5;
    }
}

if (renderBackground || renderSprites) {
    incrementX();
    if (dot == 256) {
        incrementY();
   }
}
On dot 257:

Code: Select all

if (renderBackground || renderSprites) {
    if (dot == 257) {
        setBit(address, 10, startAddress & 0x0400);
        address &= 0xFFE0;
        address |= startAddress & 0x001F;
    }
}
At the end of vblank:

Code: Select all

if (scanline == -1 && dot >= 280 && dot <= 304) {
    address &= 0x041F;
    address |= startAddress & 0x7800;
    address |= startAddress & 0x03E0;
}
I can't seem to find out what I'm missing.

Myself086
Posts: 35
Joined: Sat Nov 10, 2018 2:49 pm

Re: Donkey Kong Title Screen Filled With Zeros

Post by Myself086 » Tue Jun 09, 2020 12:11 am

It is likely due to how writes to $2007 are interpreted. Games usually clear an entire nametable by setting the address to the top left tile and writing 1kb. My only thought is that you're probably assuming writes to $2007 will cross nametables horizontally, which would create the effect of only clearing half of the visible nametable and half of another nametable.

Additionally, your left most tile is misaligned vertically.

I haven't looked at your code yet.

hypnotron
Posts: 8
Joined: Fri Apr 17, 2020 7:21 pm

Re: Donkey Kong Title Screen Filled With Zeros

Post by hypnotron » Tue Jun 09, 2020 8:26 am

hypnotron wrote:
Mon Jun 08, 2020 9:36 am
Memblers wrote:
Mon Jun 08, 2020 9:01 am
Similar symptoms were seen in this thread:
http://forums.nesdev.com/viewtopic.php?f=3&t=19926
I checked my v/t register updates against the PPU Scrolling wiki page and there don't appear to be any mistakes, although that thread did help me solve another unrelated PPU bug earlier.

(address: v)
(startAddress: t)
After BG shift register reload:

Code: Select all

void incrementX() {
    if ((address++ & 0x001F) == 0x001F) {
        --address &= 0xFFE0;
        address ^= 0x0400;
    }
}

void incrementY() {
    if ((address += 0x1000) & 0x8000) {
        address -= 0x8000; 
        u8_fast coarseY = (address & 0x03E0) >> 5;
        if (coarseY == 29) {
            address ^= 0x0800;
        }
        coarseY = coarseY == 29 || coarseY == 31 
              ? 0
              : coarseY + 1;
        address &= 0xFC1F;
        address |= coarseY << 5;
    }
}

if (renderBackground || renderSprites) {
    incrementX();
    if (dot == 256) {
        incrementY();
   }
}
On dot 257:

Code: Select all

if (renderBackground || renderSprites) {
    if (dot == 257) {
        setBit(address, 10, startAddress & 0x0400);
        address &= 0xFFE0;
        address |= startAddress & 0x001F;
    }
}
At the end of vblank:

Code: Select all

if (scanline == -1 && dot >= 280 && dot <= 304) {
    address &= 0x041F;
    address |= startAddress & 0x7800;
    address |= startAddress & 0x03E0;
}
I can't seem to find out what I'm missing.
Turns out I was missing something that, in retrospect, seems very obvious. Take a look at the first two register updates and then the third. Spot the difference? I wasn't checking if background or sprite rendering was enabled, and was clobbering PPUADDR by reloading it while Donkey Kong was writing to PPUDATA. FYI for anyone else writing an emulator, don't be afraid to log anything and everything to a file; increasing the verbosity of my emulator's log, while also increasing tedium, made detecting this error much easier.

EDIT: I also just fixed the leftmost tile alignment (if anyone's wondering, it had to do with shifting the necessary registers during the tile prefetch at end of each scanline).

Post Reply