PPU Nametables

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
PPU Nametables
by on (#90328)
I am in the process of implementing the PPU, but I am having problems trying to get the nametables to load properly. Here is a comparison of nametables for Donkey Kong on my emulator & FCEUXDSP.

Image

Would this be a result of improper initial PPU loading, or would it be changes to the nametables through PPUDATA?

I can provide more information and/or code if this is too obscure a problem to determine from the picture.

by on (#90332)
Are you certain the game is even running? It would also help if you had actual tile graphics showing.

by on (#90334)
Yes, the game is running (the debugger runs through the code).

Quote:
It would also help if you had actual tile graphics showing.

Do you mean the tile sets? Here they are:
Image

I apologize if I misunderstood you, it's been a long day.

by on (#90336)
can you post your code to draw the tile data?

by on (#90349)
Your windows are blank. I don't see Donkey Kong's graphics at all.

Again just because code is executing and not hitting a bad opcode doesn't mean the game is running. At the very least check that the contents of name table memory match what they are in FCEUX when the title screen is up. And infact if the game is running even without any input the nametable will change after awhile as the game will run an attract mode/demo. If this isn't happening then the game isn't actually running yet.

by on (#90355)
Put a screen of the game running.

by on (#90460)
I realized that the tile set preview wasn't reading the bytes correctly. Here is a screenshot of the game running with the tile sets and name tables:

Image

by on (#90462)
looks like you're reading the same row of tiles over and over... and i have no idea whats going on with your main display. again, if you can post the source code we can point out what's going wrong.

by on (#90482)
miker00lz wrote:
looks like you're reading the same row of tiles over and over... and i have no idea whats going on with your main display. again, if you can post the source code we can point out what's going wrong.


The main emu window looks like it's just displaying uninitialized (garbage) video memory.

by on (#91103)
It looks like I had overlooked two essential items: NMI & DMA.

Here is what the system looks like now:
Image
Image

As you can see, the left side and some of the top is not showing correctly. What could be causing this?

(I don't have sprites implemented yet, just the background.)

by on (#91107)
Your name table mirroring is broken. You shouldn't have 4 unique name tables unless the game is using "Four Screen Mirroring" whic is actually No Mirroring. If you fix name table mirroring you might fix those issues in the background.

by on (#91113)
MottZilla wrote:
Your name table mirroring is broken. You shouldn't have 4 unique name tables unless the game is using "Four Screen Mirroring" whic is actually No Mirroring. If you fix name table mirroring you might fix those issues in the background.


yeah, exactly.

Elessar, there are four mirroring cases you need to account for on reads/writes to/from your PPU memory.


for horizontal mirroring:
on accesses to $2400 thru $27FF, subtract $400 from the address
on accesses to $2800 thru $2BFF, subtract $400 from the address
on accesses to $2C00 thru $2FFF, subtract $800 from the address

for vertical mirroring:
on accesses to $2800 thru $2FFF, subtract $800 from the address

for one screen mirroring:
on accesses anywhere from $2000 thru $2FFF, you get the new address by AND'ing the given address by $03FF, then OR'ing that result with $2000.

and like MottZilla said, for four screen mirroring just leave the address as it is.

by on (#91114)
I will start implementing mirroring now, but that should not be causing the glitches. I have verified that all the PPU memory accesses have stayed within the $2000 nametable, and the nametable viewer I wrote displays the nametable perfectly.

EDIT: I implemented mirroring, but the glitches still remain.
Image
Image

Is there anything else that could cause this?

by on (#91118)
Memory initialization? The game probably isn't zeroing out the second nametable. If you're not initializing memory to anything, you could get glitchy areas on the second nametable.

by on (#91127)
Dwedit wrote:
Memory initialization? The game probably isn't zeroing out the second nametable. If you're not initializing memory to anything, you could get glitchy areas on the second nametable.


From experience, nametables should be initialized by the emulator with zeroes ($00), and not $FFs.

by on (#91144)
Initialized by the program? Nametables should be initialized with whatever the blank tile is in the CHR bank. This might be zeroes, or it might be space characters ($20) in a game that uses ASCII for tiles $20-$3F, or it might be $24 in a game that uses the same character encoding as Donkey Kong, Super Mario Bros., and a lot of other early NES games.

Initialized by the emulator? That depends on what make and model of RAM chip you're emulating. But make sure you write something there so that an NES game can't covertly read private data from other applications running on the same PC as the game.

by on (#91150)
Tepples, what would be the point of that? It's not like the NES game can then send that information out to the world. That is kind of funny though.

Usually people just zeroed out memory even though that is not accurate. I think FCEUX has a pattern of FFs and 00s. Other emulators initialize everything to like 55 or 53. As tepples said, the real hardware depending on the RAM chip.

by on (#91151)
I remember of a few homebrews seem glitched with $FF. OK, perhaps programming errors.

by on (#91153)
While we're talking about memory initialization: here's some trivia:

Metroid won't boot if CHR-RAM is initialized to certain values. Don't know exactly what values trigger boot failure, but for a while, FCEUX wouldn't boot Metroid if you launched it from the command line. FCEUX did not initlaize CHR-RAM at all, leaving it as whatever was in the PC's memory at the time. After FCEUX started initializing CHR-RAM, Metroid worked again.

by on (#91157)
Which shows bad programming on Nintendo's part. You should never use uninitialized memory.

by on (#91159)
I think this was possibly because the game was originally programmed for the FDS, in which RAM was supposed to have been initialised before the game booting. The programmers did overlook this important aspect when they converted the game to cart format though.

by on (#91162)
MottZilla wrote:
It's not like the NES game can then send that information out to the world

Except through steganography. In theory, it can leak data by changing the seed to generate e.g. grass tiles in CHR RAM, which would appear in a screenshot from that emulator. Or perhaps I'm just being as PARANOiD as the OpenBSD people here; any practical application would need inside information comparable to that used to make Stuxnet.

Quote:
Which shows bad programming on Nintendo's part. You should never use uninitialized memory.

Unless you're looking for signatures that game copier units are known to leave behind, such as the trampoline in RAM that they use to start executing the game.

by on (#91164)
Perhaps, that is possible. They would have to assume that RAM chips would have a specific power on state and that never could you reset the system with the wrong values in place. Really I just think it's bad code. Though that is a good point Gilbert, perhaps because it was a FDS game conversion maybe it assumes the FDS BIOS had run before it.

by on (#91166)
tepples wrote:
MottZilla wrote:
Quote:
Which shows bad programming on Nintendo's part. You should never use uninitialized memory.

Unless you're looking for signatures that game copier units are known to leave behind


Well if it's equal to those values than it is initialized.

by on (#91199)
No you don't understand. RAM is in an undetermined state on powerup or reset. You cannot assume RAM is all zeroes or all FF or any other pattern. You can check RAM to see if there is integrity markers for some sort of on Reset behavior. X-Men on Sega Genesis does this. But generally you should never use memory that has not been initialized. It could contain anything on power up/reset. Assuming a state is how you end up with software that only works on emulators that initialize this specific state. The same can be said of registers like PPU registers. Their state cannot be assumed on reset.

by on (#91203)
In short words, fill up your nametables with $00 and you should be fine. Be clear that the NES hardware might behave differently though.

by on (#91245)
If you must not read the RAM upon powerup/reset, how are you supposed to detect that the reset button was pressed? Some games do that.

by on (#91253)
It's obviously OK to do it if you're looking for signatures (which have been initialized before). What you can't do is use memory locations that have not been initialized.

by on (#91258)
Depending on particular values in the RAM for functionality is bad, I agree, but how about using the RAM contents to seed the random generator?

Is reading the RAM after poweron a bad idea on electronic basis, or is it just a bad idea because of programming practices basis? In the former case, trying to detect the reset is also a bad idea.

by on (#91264)
It's very simple. On powerup RAM could contain any value at any location. In reality it depends on the chip. I believe they generally have a certain pattern to them. This will only be the case when you power on, not when you reset as RAM contents will contain whatever was there when you reset still.

So to detect a "reset" you just need to reserve some RAM for a signature that you will set at some point in your program. The signature should be defined and not something that would possibly be the value on ram powerup. So you'd want to avoid 00 or FF, and probably F0 or 0F. The more bytes you use the more reliable it is, the easiest thing to do is just a 3 byte string. I mean you could just write the word CAT or DOG to ram and check for it on reset to detect a powerup versus just a reset. There is basically no chance ram will contain those values on powerup, only on reset after your program writes it.

Bad programming is using variables/memory without knowing they have been initialized. This is true in all programming. Unless you have reason to believe the contents are initialized or have a reason to read them. There are reasons you might but when programming a game, you generally should be sure to initialize everything. It's just basic programming.

by on (#91267)
Bisqwit wrote:
Is reading the RAM after poweron a bad idea on electronic basis

No, it's not electronically bad, if the initial value of a variable doesn't matter you can skip the initialization.

by on (#91270)
MottZilla wrote:
I mean you could just write the word CAT or DOG to ram and check for it on reset to detect a powerup versus just a reset. There is basically no chance ram will contain those values on powerup, only on reset after your program writes it.


I'm sure a million engineers in a room with a million NES could produce the word CAT or DOG in the RAM of one of them in precisely the right location in a finite amount of power-cycles' time.

:shock:

Now...if that NES also contained the 9 billion names of God in its RAM...well...then the end of the Universe is near anyway so it won't matter.

by on (#91290)
I'm talking about practically speaking judging from what I've heard, Static RAM doesn't power up to totally random values, that there is a pattern.

It's not about what someone could cook up now.

by on (#91292)
MottZilla wrote:
I'm talking about practically speaking judging from what I've heard, Static RAM doesn't power up to totally random values, that there is a pattern.

It's not about what someone could cook up now.


My post...needs more sarcasm! :D

by on (#91347)
Indeed, it doesn't always translate well in text.