Made some progress would like your PPU advice...

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
User avatar
davecom
Posts: 39
Joined: Mon Jul 16, 2018 2:57 pm

Made some progress would like your PPU advice...

Post by davecom »

Hi All,

Thanks for all of the advice about the Mac emulators. I eventually settled on Nintaco. Well, I finally got my PPU rendering some basic backgrounds (turns out I had a few CPU bugs I didn't realize before (now I'm passing everything in nestest until the first non-standard instruction) and by not turning off rendering when flags were set, scroll code was causing V to get too large). I've attached the screenshots of where I'm at now with Donkey Kong.

I figured the extremely experienced devs on here could probably take one look at these attached screenshots and instantly know what problems I should tackle next in my PPU to get it rendering backgrounds decently. My code is here:
https://github.com/davecom/DDNES

Thanks in advance!

Edit: Updated screenshots after fixed off by 1 tile error.
Attachments
dk2.png
dk2.png (22.61 KiB) Viewed 6303 times
dk1.png
dk1.png (21.05 KiB) Viewed 6303 times
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Made some progress would like your PPU advice...

Post by koitsu »

Looks like your attribute table calculation/bits are wrong, or how you're handling/doing palettes. First screenshot implies more of the former than the latter.

Edit: could also be that the attribute table you have is correct, but the palette indices (or even your palette/colour values themselves) are wrong.

Best thing to do is use an emulator like FCEUX or Nintendulator or Mesen or NO$NES to examine the relevant details using the same game + compare to your own. I've used FCEUX and NO$NES for this purpose in the past, but I imagine Mesen does a pretty good job too. But I'll help best I can:

At power-on (not reset), using ROM Donkey Kong (W) (PRG1) [!] (MD5 6d4a94c344463e562344249e18e9b99f), the palette for the title screen looks like this, starting at palette index 0:

Code: Select all

0F 2C 38 12  0F 27 27 27  0F 30 30 30  0F xx xx xx
00 25 xx xx  00 xx xx xx  00 xx xx xx  00 xx xx xx
Where xx means an uninitialised palette entry (FCEUX defaults to a dark-mid grey tone (RGB value 0x76, 0x76, 0x76), mainly to "simulate" the common "grey screen" the NES would show before the game had initialised PPU + palette + etc.), i.e. the game hasn't updated/changed/set those palette entries. On a reset, these values would remain whatever they previously were at the time of reset.

Immediately after starting the game, or during the attract demo, the palette becomes this (again starting at index 0):

Code: Select all

0F 15 2C 12  0F 27 02 17  0F 30 36 06  0F 30 2C 24
00 02 36 16  00 30 27 24  00 16 30 37  00 06 27 02
User avatar
davecom
Posts: 39
Joined: Mon Jul 16, 2018 2:57 pm

Re: Made some progress would like your PPU advice...

Post by davecom »

koitsu wrote:Looks like your attribute table calculation/bits are wrong, or how you're handling/doing palettes. First screenshot implies more of the former than the latter.

Edit: could also be that the attribute table you have is correct, but the palette indices (or even your palette/colour values themselves) are wrong.

Best thing to do is use an emulator like FCEUX or Nintendulator or Mesen or NO$NES to examine the relevant details using the same game + compare to your own. I've used FCEUX and NO$NES for this purpose in the past, but I imagine Mesen does a pretty good job too. But I'll help best I can:

At power-on (not reset), using ROM Donkey Kong (W) (PRG1) [!] (MD5 6d4a94c344463e562344249e18e9b99f), the palette for the title screen looks like this, starting at palette index 0:

Code: Select all

0F 2C 38 12  0F 27 27 27  0F 30 30 30  0F xx xx xx
00 25 xx xx  00 xx xx xx  00 xx xx xx  00 xx xx xx
Where xx means an uninitialised palette entry (FCEUX defaults to a dark-mid grey tone (RGB value 0x76, 0x76, 0x76), mainly to "simulate" the common "grey screen" the NES would show before the game had initialised PPU + palette + etc.), i.e. the game hasn't updated/changed/set those palette entries. On a reset, these values would remain whatever they previously were at the time of reset.

Immediately after starting the game, or during the attract demo, the palette becomes this (again starting at index 0):

Code: Select all

0F 15 2C 12  0F 27 02 17  0F 30 36 06  0F 30 2C 24
00 02 36 16  00 30 27 24  00 16 30 37  00 06 27 02
Thanks a lot for this, it's very helpful. My title screen palette memory matches yours exactly. My attract demo screen is very close, with just the second nibble of a few changes from 0 to F. I wonder if this is because I have a different version of the ROM. Whereas your attract demo palette is:

Code: Select all

0F 15 2C 12  0F 27 02 17  0F 30 36 06  0F 30 2C 24
00 02 36 16  00 30 27 24  00 16 30 37  00 06 27 02
Mine is:

Code: Select all

0F 15 2C 12  0F 27 02 17  0F 30 36 06  0F 30 2C 24
0F 02 36 16  0F 30 27 24  0F 16 30 37  0F 06 27 02
Since the colors are off on both my title screen and my attract screen I am thinking this is not a palette memory issue.
User avatar
davecom
Posts: 39
Joined: Mon Jul 16, 2018 2:57 pm

Re: Made some progress would like your PPU advice...

Post by davecom »

Okay, I'm an idiot. I was pulling each color directly from the NES palette (so limited to 8 colors) instead of first getting the entry from palette memory. As you can see in the attached screenshots, this is fixed now. But now I have some other problems to address, that maybe you have some insight about:
Title Screen:
- Extra white lines on the right hand side of the letters

Attract Demo
- The extra light brown line in the first set of barrels
- The extra white lines in Donkey Kong himself
- The extra red line in the oil barrel

What is the most likely cause of extra vertical lines? What's interesting is that they're different colors. I'm guessing a misalignment somewhere in the shift registers?
Attachments
dk2.png
dk2.png (21.66 KiB) Viewed 6245 times
dk1.png
dk1.png (20.91 KiB) Viewed 6245 times
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Made some progress would like your PPU advice...

Post by koitsu »

I can't tell you what the problem is, but I'd suggest looking at:

a) your drawing routine for pattern table (CHR) data,
b) any kind of calculation routine your emulator is using internally for correlating graphics on-screen <--> pattern table (CHR) data,
c) the actual CHR data (I doubt this is wrong, since for this game it's all in the ROM itself); make sure the ROM works on other emulators to rule out actual corruption (there are tons of bad ROMs floating around, that's why I gave filename AND MD5 checksum).

Honestly to me, it looks like some sort of off-by-one mistake, since it's either the first or last pixel in a tile's scanline. Edit: it looks like its the last pixel column on some tiles, i.e. the last/far right pixel.

For the title screen, the tile that makes up the word "DONKEY KONG" is tile $62 located in the 2nd pattern table. That may help you.

You should really give in and just install/use Wine and get some actual Windows emulators going to help you with analysis. You'll find FCEUX's debugger, PPU viewer, nametable viewer, and hex editor (to view different parts of memory space, including PPU) to be very helpful. Stop hemming and hawing over "a pretty UI", this is low-level work; the UI will be the last of your concerns when it comes to this type of troubleshooting, I can assure you.
User avatar
davecom
Posts: 39
Joined: Mon Jul 16, 2018 2:57 pm

Re: Made some progress would like your PPU advice...

Post by davecom »

@koitsu - thanks for the comprehensive reply. I'll look into it and report back. What's weird is it seems to only affect some tiles. If it was a generalized off by one error, I would expect to see it on almost all of the tiles... I wonder what can be off by one for only some tiles... I'll have to do some investigating.
koitsu wrote:You should really give in and just install/use Wine and get some actual Windows emulators going to help you with analysis. You'll find FCEUX's debugger, PPU viewer, nametable viewer, and hex editor (to view different parts of memory space, including PPU) to be very helpful. Stop hemming and hawing over "a pretty UI", this is low-level work; the UI will be the last of your concerns when it comes to this type of troubleshooting, I can assure you.
It's not just the UI, it's the pain of having to install Wine which I recently uninstalled. I'm using Nintaco now which actually has all of the features you mentioned. But I will checkout FCEUX on my Linux or Window machine as well to compare. Thanks again.
User avatar
Banshaku
Posts: 2417
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Re: Made some progress would like your PPU advice...

Post by Banshaku »

If you don't like the command line based wine you can use wine bottler instead:

http://winebottler.kronenberg.org/

I have been using it at work for many years and it quite easy to use. The latest dev version support 2.0 too.
User avatar
davecom
Posts: 39
Joined: Mon Jul 16, 2018 2:57 pm

Re: Made some progress would like your PPU advice...

Post by davecom »

Banshaku wrote:If you don't like the command line based wine you can use wine bottler instead:

http://winebottler.kronenberg.org/

I have been using it at work for many years and it quite easy to use. The latest dev version support 2.0 too.
Yeah I've used WineBottler before and it's pretty good.
User avatar
davecom
Posts: 39
Joined: Mon Jul 16, 2018 2:57 pm

Re: Made some progress would like your PPU advice...

Post by davecom »

Okay, I figured it out. The problem was that my high tile byte calculations were off by 1 when I was merging them into the shift register for rendering. Apparently a shift by a negative number is undefined in C, so it's a hard error to spot.

My old code looked like this:

Code: Select all

for (int i = 7; i >= 0; i--) {
    temp_data <<= 4;		                        
    temp_data |= ((low_tile_byte & (1 << i)) >> i) | ((high_tile_byte & (1 << i)) >> (i - 1)) | (attribute_table_byte );
}
tile_data |= temp_data;
Where tile_data is a 64-bit unsigned integer and temp_data is a 32-bit unsigned integer. Can you spot the error? What happens when i is 0? My new code looks like this:

Code: Select all

for (int i = 7; i >= 0; i--) {
    temp_data <<= 4;
    temp_data |= ((low_tile_byte & (1 << i)) >> i);
    if (i > 0) {
        temp_data |= ((high_tile_byte & (1 << i)) >> (i - 1));
    } else {
        temp_data |= ((high_tile_byte & (1 << i)) << 1);
    }
    temp_data |= attribute_table_byte;
}
tile_data |= temp_data;
That was a subtle bug. Now I'm rendering Donkey Kong backgrounds correctly. Before I move on to sprites, what other Mapper 0 games do you recommend for testing when you have no sprites implemented and no controls implemented? Should I run any of the tests here:
https://github.com/christopherpow/nes-test-roms

Basically, I'm looking for background only tests.
Attachments
dk2.png
dk2.png (21.5 KiB) Viewed 6164 times
dk1.png
dk1.png (22.21 KiB) Viewed 6164 times
User avatar
zeroone
Posts: 939
Joined: Mon Dec 29, 2014 1:46 pm
Location: New York, NY
Contact:

Re: Made some progress would like your PPU advice...

Post by zeroone »

davecom wrote:

Code: Select all

for (int i = 7; i >= 0; i--) {
    temp_data <<= 4;
    temp_data |= ((low_tile_byte & (1 << i)) >> i);
    if (i > 0) {
        temp_data |= ((high_tile_byte & (1 << i)) >> (i - 1));
    } else {
        temp_data |= ((high_tile_byte & (1 << i)) << 1);
    }
    temp_data |= attribute_table_byte;
}
tile_data |= temp_data;
Your code might benefit from some precomputed lookup tables (LUT), each containing 256 elements. For example, a LUT for reversing the bits in a byte. And, 2 other LUTs for doing those bit extractions.
User avatar
davecom
Posts: 39
Joined: Mon Jul 16, 2018 2:57 pm

Re: Made some progress would like your PPU advice...

Post by davecom »

zeroone wrote:
davecom wrote:

Code: Select all

for (int i = 7; i >= 0; i--) {
    temp_data <<= 4;
    temp_data |= ((low_tile_byte & (1 << i)) >> i);
    if (i > 0) {
        temp_data |= ((high_tile_byte & (1 << i)) >> (i - 1));
    } else {
        temp_data |= ((high_tile_byte & (1 << i)) << 1);
    }
    temp_data |= attribute_table_byte;
}
tile_data |= temp_data;
Your code might benefit from some precomputed lookup tables (LUT), each containing 256 elements. For example, a LUT for reversing the bits in a byte. And, 2 other LUTs for doing those bit extractions.
Thanks, that makes sense. I could see a LUT being a bit more readable and a bit more performant. Since this is just a learning project and I'm really not worrying about performance, I'll probably leave it since it's working, but if I was doing a more serious emulator, I probably would make the change.
Post Reply