Stuck at implementing PPU

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
User avatar
smora015
Posts: 3
Joined: Tue Sep 16, 2014 7:52 pm
Location: Riverside, CA

Stuck at implementing PPU

Post by smora015 »

Hey guys,


So I just finished writing a stable 6502 core in C and want to move on to the graphics aspect of the NES. Thing is, I'm a little stuck in terms of how everything gets rolling during start-up, though...

First and foremost, how does the Name Table get populated during start up? I've gone through numerous documentation but none of it is exactly specific on what happens. What exactly does the name table contain? I don't understand how it contains enough data to reference both sprites and background data.
tepples
Posts: 22861
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Stuck at implementing PPU

Post by tepples »

smora015 wrote:First and foremost, how does the Name Table get populated during start up?
Usually by loops copying blocks of data or writing blocks of repeating tiles.
I've gone through numerous documentation but none of it is exactly specific on what happens. What exactly does the name table contain?
The first 960 bytes are the tile numbers for each 8x8 pixel area: left to right, in rows from top to bottom. The rest is attribute data, which specifies which color set is assigned to each 16x16 pixel area.
I don't understand how it contains enough data to reference both sprites and background data.
Sprites have almost* nothing to do with the nametable. They don't interact with the background at all except at the compositor stage of PPU processing, which combines the sprites with the background.
User avatar
tokumaru
Posts: 12536
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Stuck at implementing PPU

Post by tokumaru »

smora015 wrote:First and foremost, how does the Name Table get populated during start up?
The game does it, not the emulator. The 6502 program writes to specific memory locations ($2000 to $2007, plus mirrors) to communicate with the PPU, and through these registers they can select an address in PPU memory and then send data to be written from this address on.

Maybe what's confusing you is that in some cases, part of the PPU memory is filled automatically, but this only happens for pattern tables in case of CHR-ROM. The rest of the PPU memory, and even the pattern tables in case of CHR-RAM, is completely maintained by the game program running on the CPU.
What exactly does the name table contain?
On power up, the contents are undefined and somewhat random, the NES itself doesn't initialize the PPU memory at all. After that, it contains whatever the game program puts in there, and it changes often (several times per second, depending on the game) during gameplay. Games that scroll will update the name tables more frequently, because new parts of the level are drawn as the screen scrolls.
I don't understand how it contains enough data to reference both sprites and background data.
The name tables have nothing to do with sprites. It goes like this: The pattern tables hold the actual tile graphics that will be used for the background and sprites. The name tables are arrays of tile indices, that work like walls you can "glue" tiles to in order to form larger images. The attribute tables let you select what palettes will be used for the tiles in the name tables. The OAM is somewhat analogous to the name table, but for sprites. Since sprites are not aligned in a grid like the background, their attributes include X and Y coordinates, so the PPU knows where to draw them. A few more attributes are necessary for sprites, like X and Y flipping and priority, which are packed in the same byte that selects their palette.
User avatar
smora015
Posts: 3
Joined: Tue Sep 16, 2014 7:52 pm
Location: Riverside, CA

Re: Stuck at implementing PPU

Post by smora015 »

tepples wrote:The first 960 bytes are the tile numbers for each 8x8 pixel area: left to right, in rows from top to bottom. The rest is attribute data, which specifies which color set is assigned to each 16x16 pixel area.
Okay, now I get why each Name Table is 0x3C0 in length (not including the attribute data.) This makes soooo much more sense! I was under the impression that the Name Tables hold both BG and Sprite data, and once its time for the PPU to render all the scanlines, it would start reaching for the actual data and glue together palette data as well.

I'm assuming you only need 1 byte to address the tile because there's only 256 total tiles per Pattern Table?
tokumaru wrote: The game does it, not the emulator. The 6502 program writes to specific memory locations ($2000 to $2007, plus mirrors) to communicate with the PPU, and through these registers they can select an address in PPU memory and then send data to be written from this address on.

Maybe what's confusing you is that in some cases, part of the PPU memory is filled automatically, but this only happens for pattern tables in case of CHR-ROM. The rest of the PPU memory, and even the pattern tables in case of CHR-RAM, is completely maintained by the game program running on the CPU.
Awesome, this is what I was assuming, but I was a little confused when using FCEUX's debugger. I noticed that during the first few instructions, for say, Super Mario Bros., it loops around, waiting for the VBlank flag to be set. But I couldn't catch when the Name Table got populated for the title screen, so I was very confused as to how it worked. It seemed almost like magic to me =/

I'm probably not putting in the right breakpoints somewhere. At what point should I be checking for the program to populate the Name Table with the intro screen?

Thanks so much guys, this saved me tons of hours of pulling my hair out...
tepples
Posts: 22861
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Stuck at implementing PPU

Post by tepples »

Lots of $2007 writes in a row often means pumping data into nametables.
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Stuck at implementing PPU

Post by koitsu »

smora015 wrote:I'm probably not putting in the right breakpoints somewhere. At what point should I be checking for the program to populate the Name Table with the intro screen?
The subject has now changed from "how do I implement the PPU in my emulator" to "how do I use FCEUX's debugger to look at Super Mario Brothers". *confused look* :P

To answer the latter question: this is fairly easy -- you set up breakpoints on writes to PPU address ranges. Pay attention to the Add Breakpoint dialog and you'll see there's an Address range at the top, and a radio button that lets you pick PPU Mem. That's what you want.

You'll be inclined to look for writes to, say, PPU addresses $2000-23FF which correlate with the first nametable. But due to how mirroring is configured, and depending on how the game is programmed or what their intentions are, and some of the scroll settings, they might actually be writing to $2400-27FF, or $2800-2BFF, or $2C00-2FFF.

So you may want to just block on addresses $2000-2FFF.

The next thing you're probably going to think is "okay great!", go off and do it, then (probably, I'm speculating) drops to the debugger and does a ton of $2007 writes and a bunch of other complex things. You'll go through the loop a ton of times, and eventually it'll finish... except the screen doesn't contain the title screen you expect. Instead it just shows nothing.

This is because you're thinking the very first time the game starts + first time it starts writing to nametables, it's going to draw a title screen. Don't think that / don't assume that. It's very possible the game is zeroing out parts of the unused nametables (and possibly the active one -- i.e. blanking the screen), or setting up something else first. So really you end up having to step through a few situations until you find what you want. That is simply the art of debugging/reverse-engineering. It's a huge time sink.

Furthermore, many/most games have a "common writing routine" that they JSR to do a bunch of PPU writes, based on some values they write dynamically into zero page first. So what you end up having to do there is figure out what's written to those zero page addresses, then figure out where within the preceding code that was done and break on that (as a ROM execution breakpoint), often by examining the stack (because of the JSR, or multiple JSRs). Again: the art of debugging/reverse-engineering.

So what can you do to help narrow down the conditionals so you get something accurate, rather than spend 90 hours sitting around in loops + clicking buttons + praying? Gotta use your brain a little bit, along with knowing FCEUX's debugger:

The Super Mario Brothers title screen has some text that reads "(C)1985 NINTENDO" on it. It's pretty likely that if we could break on when it writes the copyright symbol (tile) to the screen, that we'd have a "general" idea of where the routine might be.

I'll focus on the ROM titled Super Mario Bros. (JU) [!].nes (you have to give this because there are a billion ROMs floating around and not all are the same/have the same addresses. SMB is the worst of the bunch, there must be a hundred+ ROMs of this damn thing).

Load it up in FCEUX and when the title screen is drawn, hit Pause (on your keyboard) and the emulation will pause.

Now go to Debug / Name Table Viewer. You'll see the title screen in the upper left nametable ($2000-23FF) as well as in the lower left nametable ($2800-2BFF). This is what I was talking about, re: mirroring. At this point we don't know if the game is writing to PPU memory in the $2000-23FF region or the $2800-2BFF region. But here's what we do know:

If you move your mouse over the copyright symbol/tile, you'll see the debugger say Tile: $CF. Okay, so we know the copyright symbol tile is tile $CF -- which means in turn we know that that's a byte we could "key off of" when doing a breakpoint on a PPU write. But $CF just a value; that same tile value could be used at any other time but with different CHR data (potentially), so we can't just go off of that.

The other thing we know is where on the screen it writes $CF: again moving your mouse over the copyright symbol, in the upper left nametable you'll see it's at PPU address $21ED, and in the lower left it's at $29ED (makes perfect sense given the game's mirroring).

Now we know what we can add 2 breakpoints on: a write to PPU address $21ED, and another breakpoint with a write to $29ED. But hold on.

You would also think you could use a conditional value of #CF -- not $CF or #$CF (the syntax here matters greatly because of how FCEUX's debugger works. Read the documentation under Help / Debugger, specifically the stuff under Conditional Breakpoints. The syntax is very very sensitive and it's easy to mess up.) But guess what: nope -- it doesn't work. Feature/bug in the debugger. Nothing we can do about it.

So what, are we just gonna blindly break on every time something writes to $21ED or $29ED? Sure, that's possible... or we could make an assumption -- the assumption that the $CF tile value is in the accumulator (hoping it's not in X or Y when writing to $2007). So we add a conditional of A == #CF (again note syntax)

I'll save you some time and a breakpoint: the title screen code writes to the $21xx range, not $29xx. (I already took the time to look)

So we add a breakpoint when PPU memory is written to at address $21ED, with the conditional of the accumulator containing the value $CF. Crossing fingers. Press Pause (to resume emulation), then choose NES / Reset. (BTW, doing a NES / Reset while the debugger has tripped a breakpoint won't work -- you need to go into the debugger and click Run for it to resume. Just the way it works. It's easy to forget this when doing NES / Reset.)

Bam -- we get our first breakpoint hit:

Code: Select all

 00:8EB6:B0 01     BCS $8EB9
 00:8EB8:C8        INY
 00:8EB9:B1 00     LDA ($00),Y @ $03E5 = #$CF
>00:8EBB:8D 07 20  STA $2007 = #$FF
 00:8EBE:CA        DEX
 00:8EBF:D0 F5     BNE $8EB6
But is this the right one? The emulator just shows kind of a black line on the blue background. Easy enough: go into Debug / Name Table Viewer again and take a look at the "crosshair" (this is basically where the PPU internally is pointing to, raster-wise, if you were to write to it). Hmm, that's at the exact location the copyright tile would be at... so let's click Run and see what happens.

Imagine that -- the title screen is drawn and the game picks up where it left off. Okay, so now you have some information: the code being used to draw the title screen is within that $8EB9 area of ROM.

If you look closely however, you'll see what it's doing: it's doing an indirect indexed read from the 16-bit address stored at ZP locations $00 and $01, which FCEUX is nice enough to inform you is address $03E5 -- that's in normal RAM. So we can safely assume the game pre-populates a part of RAM with the nametable contents (or maybe just some of the contents, i.e. a little bit at a time -- we don't know)

If we look down a little ways more, we can see that this is certainly just a generic drawing routine used for things, because the rest of the code has:

Code: Select all

 00:8EC1:38        SEC
 00:8EC2:98        TYA
 00:8EC3:65 00     ADC $0000 = #$00
 00:8EC5:85 00     STA $0000 = #$00
 00:8EC7:A9 00     LDA #$00
 00:8EC9:65 01     ADC $0001 = #$4F
 00:8ECB:85 01     STA $0001 = #$4F
 00:8ECD:A9 3F     LDA #$3F
 00:8ECF:8D 06 20  STA $2006 = #$00
 00:8ED2:A9 00     LDA #$00
 00:8ED4:8D 06 20  STA $2006 = #$00
 00:8ED7:8D 06 20  STA $2006 = #$00
 00:8EDA:8D 06 20  STA $2006 = #$00
 00:8EDD:AE 02 20  LDX $2002 = #$50
 00:8EE0:A0 00     LDY #$00
 00:8EE2:B1 00     LDA ($00),Y @ $4F03 = #$FF
 00:8EE4:D0 AC     BNE $8E92
 00:8EE6:8D 05 20  STA $2005 = #$00
 00:8EE9:8D 05 20  STA $2005 = #$00
 00:8EEC:60        RTS -----------------------------------------
Last line being the most important one. Okay, so we know this is a routine that almost certainly JSR'd into, and that's confirmed by another fact: when the breakpoint hits, the stack contains the following values:

Code: Select all

C5,80,A5,57,80
For whatever reason the stack dump in FCEUX is backwards compared to what I'd expect -- I'd expect most recent stack values to be shown on the right, i.e. appended to that list, but it's the other way around. Most recent values are on the left, e.g. the values $C5 and $80.

That sure looks like a ROM address, does it not? So given that information, we can safely assume immediately preceding $80C5 is where it does a JSR to somewhere around/near where our breakpoint. So in the debugger, we go looking around $80C5 or so:

Code: Select all

 00:80BE:BD 6D 80  LDA $806D,X @ $807B = #$8D
 00:80C1:85 01     STA $0001 = #$03
 00:80C3:20 DD 8E  JSR $8EDD
 00:80C6:A0 00     LDY #$00
 00:80C8:AE 73 07  LDX $0773 = #$05
And there we have it -- JSR $8EDD. That's pretty close to where the breakpoint broke. The "drawing routine" is fairly large, so if you look closely you'll see it actually branches backwards (with BNE) into where our breakpoint was or thereabouts:

Code: Select all

 00:8EDD:AE 02 20  LDX $2002 = #$10
 00:8EE0:A0 00     LDY #$00
 00:8EE2:B1 00     LDA ($00),Y @ $03E5 = #$CF
 00:8EE4:D0 AC     BNE $8E92
Anyway, you get the idea now, and I've spent the past 60 minutes typing this up, so I think that's really enough time to dedicate to this particular task. You can dig around yourself and figure out the rest given the above methodology, I think. (I swear I should bill people for my time... :P Haha)

Back to emulation: if you want my advice: do not focus on Super Mario Brothers as your first game to get emulated. Focus on games like Mario Brothers (the original, not Super), Pinball, or Donkey Kong. SMB is kind of a pain in the ass. When you get the others working, then try to accomplish doing SMB. (For example, I'll be surprised if your 6502 emulation core is actually correct -- people keep getting ADC/SBC wrong, or having weird quirky flag behaviour problems that cause weird things to happen, like a ball shooting off diagonally somewhere and it's all because of a single bug in a single opcode). Start simple -- SMB is not simple. :)

Edit: Fixed 1995 typo (should be 1985); thanks Quietust!
User avatar
Quietust
Posts: 1956
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: Stuck at implementing PPU

Post by Quietust »

koitsu wrote:The Super Mario Brothers title screen has some text that reads "(C)1995 NINTENDO" on it. It's pretty likely that if we could break on when it writes the copyright symbol (tile) to the screen, that we'd have a "general" idea of where the routine might be.
I'll assume you meant "1985". It's also useful to remember that the values being written are not ASCII, but are instead based on the pattern tiles located in CHR ROM; in this case, the copyright symbol is 0xCF.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Stuck at implementing PPU

Post by koitsu »

Quietust wrote:
koitsu wrote:The Super Mario Brothers title screen has some text that reads "(C)1995 NINTENDO" on it. It's pretty likely that if we could break on when it writes the copyright symbol (tile) to the screen, that we'd have a "general" idea of where the routine might be.
I'll assume you meant "1985". It's also useful to remember that the values being written are not ASCII, but are instead based on the pattern tiles located in CHR ROM; in this case, the copyright symbol is 0xCF.
Yeah I meant 1985, sorry. And yeah, like I described in my debugging step-by-step, the tile value is $CF at that time.
User avatar
smora015
Posts: 3
Joined: Tue Sep 16, 2014 7:52 pm
Location: Riverside, CA

Re: Stuck at implementing PPU

Post by smora015 »

Thanks for the amazing help guys, I owe you guys big time. :)

And good point with starting out with a simpler game. I know lots of debugging awaits for me, but this cleared up so much haha. And I'm sure I have some bugs with my CPU, but its kinda hard to check them out if I don't have any sort of graphics implemented.
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Stuck at implementing PPU

Post by koitsu »

Totally valid points!

And yeah, just based on my own experience from working on emulators long ago, I'd suggest using Mario Bros as a base test, or any of the first-gen games (yeah I know SMB was first-gen, but it's complex). Try things like Nuts & Milk, Clu-Clu Land, Donkey Kong, Ice Hockey -- games like that. Go for NROM (mapper #0 / "no mapper") games for starters.

When you get around to implementing mappers, I'd suggest doing MMC1 first, then try giving Zelda (#1) a try -- it tends to act as somewhat of an interesting subject for scrolling (I think horizontally -- I believe the game changes mirroring from H to V in real-time) and PPU behaviour.
tepples
Posts: 22861
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Stuck at implementing PPU

Post by tepples »

Super Mario Bros. was an NES launch title, but it arrived about two years into the original Famicom's life. I'd agree that Donkey Kong and other 1983-1984 Famicom games, almost all of which are NROM-128, would probably be the best way to start.
User avatar
MottZilla
Posts: 2837
Joined: Wed Dec 06, 2006 8:18 pm

Re: Stuck at implementing PPU

Post by MottZilla »

Donkey Kong and Donkey Kong Jr are great early test games since they don't require much to be implemented to function. Donkey Kong was my original test game when I first tried writing an emulator.

SMB should be considered the next step up since it has a number of things that need to be working for it to work properly. I think even just Mario Bros had something else, PPU reading and the "delay" needs to be right. If you have not implemented the ability to read name tables I think all characters fall off the screen or something. I can't recall exactly. SMB has the sprite hit flag plus screen splitting to be dealt with.

So in some ways it might be easier to get a game like Contra or Mega Man running than SMB since they don't have those issues.
Sik
Posts: 1589
Joined: Thu Aug 12, 2010 3:43 am

Re: Stuck at implementing PPU

Post by Sik »

How does Pinball fare? I know somebody who used that to test his emulator.

Also yeah, this is one of my problems with the wiki, it tells people to avoid Super Mario Bros as their first game because of how hard it can be to get emulated, but it never gives any suggestions about which games are easy ones to start with (but then again, simple test programs are likely going to be even easier to start testing with).

Anyway, should the wiki contain a list of which games are the easiest to get running?
tepples
Posts: 22861
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Stuck at implementing PPU

Post by tepples »

Sik wrote:Also yeah, this is one of my problems with the wiki, it tells people to avoid Super Mario Bros as their first game because of how hard it can be to get emulated, but it never gives any suggestions about which games are easy ones to start with
You're referring to Tricky, right? You could always post your problem on the talk page where people who edit the wiki will see it. That's why I left talk pages open to anonymous editing.
Post Reply