Making a basic PPU (Fully working CPU)

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

nuker
Posts: 11
Joined: Tue Apr 25, 2017 1:10 pm

Making a basic PPU (Fully working CPU)

Post by nuker »

Hi guys,

I have a fully working and tested 6502 CPU working. Now I'd like to move on to the PPU. I've read the references on this site as well as many others. However, many of them seem extremely complex and go into detail about various features that dissuade me from even trying to make a working PPU. Therefore, I was wondering what the steps to making a basic PPU would be? I've already read in the CHR ROM data and set up the basic registers. My short term goal would be to simply get the start screen of super mario bros showing up. After that, I'd like to get super mario bros working completely. Only then do i want to worry about the complex potential features that would allow any game to work.

Thanks!
calima
Posts: 1745
Joined: Tue Oct 06, 2015 10:16 am

Re: Making a basic PPU (Fully working CPU)

Post by calima »

Mario uses many of the complex features, so targeting it as the first game wouldn't save much.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Making a basic PPU (Fully working CPU)

Post by tokumaru »

The simplest thing you can do to get games to display something is to first implement the PPU registers ($2000-$2007) to make sure that the basic settings work (pattern table addresses, sprite size, NMI generation, scroll, etc.) and that VRAM can be written to and read from. Then, you can create a simple function to draw a full frame at once, and call it 60 times per second, without bothering with CPUxPPU synchronization or with the exact processes the PPU uses to render pictures. You can do it at a higher level, gathering data from the pattern, name and attribute tables, OAM and palette RAM, and render a full frame. This should be enough to run simpler games, mainly those that don't use raster effects. More complex games might work to some extent, depending on when in the frame you sample the PPU data/settings for rendering.

Then you can start to implement the actual PPU behavior, making it run alongside the CPU and respect the real duration and order of all memory accesses and other processes (such as sprite evaluation). Depending on the level of accuracy (or performance) you're going for, you may get away with doing things 1 scanline at a time, rather than 1 pixel at a time.
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Making a basic PPU (Fully working CPU)

Post by tepples »

I agree with calima: Don't use Super Mario Bros. for initial testing, as it uses too much of the PPU's capability. Use something simpler, such as Concentration Room.
nuker
Posts: 11
Joined: Tue Apr 25, 2017 1:10 pm

Re: Making a basic PPU (Fully working CPU)

Post by nuker »

Thanks everyone! I very much appreciate the replies and advice.
tokumaru wrote:The simplest thing you can do to get games to display something is to first implement the PPU registers ($2000-$2007) to make sure that the basic settings work (pattern table addresses, sprite size, NMI generation, scroll, etc.) and that VRAM can be written to and read from. Then, you can create a simple function to draw a full frame at once, and call it 60 times per second, without bothering with CPUxPPU synchronization or with the exact processes the PPU uses to render pictures. You can do it at a higher level, gathering data from the pattern, name and attribute tables, OAM and palette RAM, and render a full frame. This should be enough to run simpler games, mainly those that don't use raster effects. More complex games might work to some extent, depending on when in the frame you sample the PPU data/settings for rendering.

Then you can start to implement the actual PPU behavior, making it run alongside the CPU and respect the real duration and order of all memory accesses and other processes (such as sprite evaluation). Depending on the level of accuracy (or performance) you're going for, you may get away with doing things 1 scanline at a time, rather than 1 pixel at a time.
This really helps! I still am a little confused on the basic memory layout. What exactly is stored in the ROM vs the VRAM? Where is the code that controls what happens with the graphics? Is it all CPU code and are all the sprites etc controlled through writes to 2000-2008 or is it like the CPU where the PPU has its own instruction set that I read from the ROM?

At a high level I understand what OAM, and tiles etc are but i'm kind of confused how they all fit in together and what code is responsible for moving the Mario sprite up when it jumps.
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Making a basic PPU (Fully working CPU)

Post by tepples »

On the NES PPU:
$0000-$1FFF contains pattern tables, which define what each tile looks like. Each of the 512 tiles accessible at any given moment is 16 bytes in size.
$2000-$2FFF contains nametables, which define which tiles to use for each part of the background.

On most cartridges:
$0000-$1FFF is ROM or RAM in the cartridge.
$2000-$2FFF is RAM in the Control Deck. Only two of the four 1 KiB ($400 byte) regions are distinct; the other two are "mirrors", or the same piece of memory appearing at different parts of address space.

In either case, if it is RAM, the CPU copies data into RAM using $2006 and $2007 before displaying anything.
Pokun
Posts: 2681
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Making a basic PPU (Fully working CPU)

Post by Pokun »

If you by ROM means the PRG-ROM on the cartridge, it's where all the program code executed by the CPU is. CHR-ROM (also on the cartridge) is best viewed as part of VRAM. And if the cartridge has CHR-RAM it's writeable VRAM by the program, but from the PPUs perspective it's still just part of VRAM.

VRAM holds nametables (scrollable background screen data), pattern tables (the shape definitions for background characters and sprites) and palettes. The pattern tables are in the CHR-ROM/CHR-RAM that comes with the cartridge (although this doesn't make a difference for the PPU).
Sprites attributes are in OAM which is a separate memory from VRAM but it has a similar purpose, just only for sprite attributes.

What makes Mario go up? The program code runs and notices that the player presses the jump button, it processes all the necessary logic to jump and finally writes whatever changed on Mario's sprite to the OAM when the next vblank happens (usually via OAM-DMA). The PPU uses the information currently in OAM and VRAM to draw the screen every frame. There's also a bunch of internal memories and registers in the PPU that I don't know much about (I mostly only knows about things that a NES programmer needs to know). But you might not need to implement everything accurately right away, just get basic VRAM and OAM content to appear on screen.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Making a basic PPU (Fully working CPU)

Post by tokumaru »

nuker wrote:I still am a little confused on the basic memory layout. What exactly is stored in the ROM vs the VRAM?
The video memory is separate from CPU memory and has the following layout (copied from the wiki):

$0000-$0FFF: Pattern table 0
$1000-$1FFF: Pattern Table 1
$2000-$23FF: Nametable 0
$2400-$27FF: Nametable 1
$2800-$2BFF: Nametable 2
$2C00-$2FFF: Nametable 3
$3000-$3EFF: Mirrors of $2000-$2EFF
$3F00-$3F1F: Palette RAM indexes
$3F20-$3FFF: Mirrors of $3F00-$3F1F

The pattern tables and the name tables can be RAM or ROM (defined by the cartridge), but ROM name tables are very rare (maybe only 1 or 2 games have them).
Where is the code that controls what happens with the graphics? Is it all CPU code and are all the sprites etc controlled through writes to 2000-2008
This. The game code running in the CPU sets up all the backgrounds, sprites and various PPU configurations through the PPU registers. The PPU does perform a hardcoded sequence of operations by itself that involves reading data from all the tables in order to generate images, and this is the complicated part.
At a high level I understand what OAM, and tiles etc are but i'm kind of confused how they all fit in together and what code is responsible for moving the Mario sprite up when it jumps.
The OAM is basically a list indicating where on the screen each sprite must be rendered, what tiles they use, and a few other parameters (palette, flipping, priority). This information is calculated by the game code and uploaded to the PPU via OAM DMA. When emulating the PPU, all you have to do is interpret this data as documented and draw all the sprites in the correct positions.

When the PPU draws sprites, it performs an operation called "sprite evaluation". Every scanline, it goes through the OAM comparing the current scanline number against the Y coordinates of each OAM entry, to detect whether they're in range or not. For each entry, it calculates Scanline - SpriteY, and when the result is smaller than the sprite height (8 or 16 pixels, as selected through register $2000), that means the sprite is in range, and that's the index of the sprite line to draw. The information about the sprite is then copied to secondary OAM (there's enough space and time to do this for 8 sprites at most), and when the scanline ends, the graphics are copied from the pattern tables so they can be drawn on the next scanline.

If you're shooting for accuracy, you have to research each of these steps very well, to make sure everything happens the same way and at the same time as in a real PPU. But if accuracy is not a priority, you can do what I said before and high-level all of this: just scan all 64 OAM entries and draw the 64 sprites at once at the specified positions. It should work for most games, but there are a few that manipulate rendering parameters mid-frame that will require you to respect the actual timing of the PPU.
nuker
Posts: 11
Joined: Tue Apr 25, 2017 1:10 pm

Re: Making a basic PPU (Fully working CPU)

Post by nuker »

Thank you so much! That really illuminated a lot of it for me. I now understand how given the pattern tables, name tables, OAM, etc I can draw the screen.
tokumaru wrote:
This. The game code running in the CPU sets up all the backgrounds, sprites and various PPU configurations through the PPU registers. The PPU does perform a hardcoded sequence of operations by itself that involves reading data from all the tables in order to generate images, and this is the complicated part.
One last part I'm still a little unclear on now is how exactly is the nametable, etc populated into memory. Are you saying that is all handled by the game code and I don't need to handle it? I still don't know how to go from startup to having the nametables etc all setup in memory.

I do however understand how to go from having everything setup to drawing it now.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Making a basic PPU (Fully working CPU)

Post by tokumaru »

All these tables are just memory, so the same way you don't have to worry about how games populate regular RAM with lives, levels, object data, etc., you don't have to care about how they fill the name/attribute tables or the rest of VRAM. If the CPU is working, the correct values will end up in VRAM.

All you have to do is implement the interface through which the CPU writes to VRAM, since they're not directly connected. Basically you have to implement registers $2006, $2007, and the VRAM increment bit of $2000.
nuker
Posts: 11
Joined: Tue Apr 25, 2017 1:10 pm

Re: Making a basic PPU (Fully working CPU)

Post by nuker »

tokumaru wrote:All these tables are just memory, so the same way you don't have to worry about how games populate regular RAM with lives, levels, object data, etc., you don't have to care about how they fill the name/attribute tables or the rest of VRAM. If the CPU is working, the correct values will end up in VRAM.

All you have to do is implement the interface through which the CPU writes to VRAM, since they're not directly connected. Basically you have to implement registers $2006, $2007, and the VRAM increment bit of $2000.
Okay, that makes a lot more sense! Confusion sorted out.
Pokun
Posts: 2681
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Making a basic PPU (Fully working CPU)

Post by Pokun »

$2006 and $2007 are only for VRAM (background and palettes) though. For sprites you have to implement the same thing for OAM which is using $2003 and $2004, and also $4014 for OAM-DMA.

Edit: Note that $2004 seems to be buggy and also not readable on all versions of the PPU (my Famicom can't read it for instance). Most games never use it though, as they use OAM-DMA to fill OAM.
User avatar
MottZilla
Posts: 2837
Joined: Wed Dec 06, 2006 8:18 pm

Re: Making a basic PPU (Fully working CPU)

Post by MottZilla »

tokumaru wrote:The simplest thing you can do to get games to display something is to first implement the PPU registers ($2000-$2007) to make sure that the basic settings work (pattern table addresses, sprite size, NMI generation, scroll, etc.) and that VRAM can be written to and read from. Then, you can create a simple function to draw a full frame at once, and call it 60 times per second, without bothering with CPUxPPU synchronization or with the exact processes the PPU uses to render pictures. You can do it at a higher level, gathering data from the pattern, name and attribute tables, OAM and palette RAM, and render a full frame. This should be enough to run simpler games, mainly those that don't use raster effects. More complex games might work to some extent, depending on when in the frame you sample the PPU data/settings for rendering.

Then you can start to implement the actual PPU behavior, making it run alongside the CPU and respect the real duration and order of all memory accesses and other processes (such as sprite evaluation). Depending on the level of accuracy (or performance) you're going for, you may get away with doing things 1 scanline at a time, rather than 1 pixel at a time.
I think this is a great way to start out. Many games can work pretty well with this simplified approach. Donkey Kong & Donkey Kong Jr., Mario Bros (the arcade port, not Super Mario Bros), Sqoon maybe. Pac-Man most likely. Even games like Mega Man and Contra work pretty well this way. Castlevania can work if you don't mind the scoreboard section scrolling.

So to start it's a good idea to get the PPU registers working so you have the NameTables and Palette data populated giving you something to work with. You could decode all the tiles before hand to something easier for you to work with. If you like Donkey Kong or Donkey Kong Jr. I highly recommend them as early emulation test games. I used both of them for testing in my first emulator.
nuker
Posts: 11
Joined: Tue Apr 25, 2017 1:10 pm

Re: Making a basic PPU (Fully working CPU)

Post by nuker »

MottZilla wrote:
tokumaru wrote: So to start it's a good idea to get the PPU registers working so you have the NameTables and Palette data populated giving you something to work with. You could decode all the tiles before hand to something easier for you to work with. If you like Donkey Kong or Donkey Kong Jr. I highly recommend them as early emulation test games. I used both of them for testing in my first emulator.
Thank you for the help guys! I went ahead and implemented a bare bones PPU. Just to see if it worked at all, i hardcoded it to always render the first nametable. I also made it so only the "background" pixels are rendered (value 0 in pattern table).

However, when i run SMB ROM, i just get a weird grey pattern to show up before the entire output going grey. I just wanted to know if anyone had any ideas or tips.

I've attached the weird grey pattern. One can clearly see the alphabet mirrored on it in the center.
Capture.JPG
Capture.JPG (56.08 KiB) Viewed 4566 times
To be clear, it shows this for a few frames before showing nothing but grey.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Making a basic PPU (Fully working CPU)

Post by tokumaru »

I believe it has been pointed out that SMB isn't a good test subject for a barebones PPU implementation. It relies on raster effects (status bar), pallette mirroring, VRAM/ROM readback, scrolling... Better start with something simpler, like Donkey Kong or Mario Bros., which have already been suggested.

It doesn't mean you will get nothing out of SMB, as even the simple approach to PPU rendering should show something discernible for SMB, it's just that it may be harder to debug the initial PPU implementation using a game that relies on more advanced PPU features. There certainly is something wrong there, but the problem may be easier to catch if you try a less demanding game.

EDIT: Those patterns do resemble the pattern tables of SMB, but I don't think there's any reason for them to show up like that in the final emulated picture.
Post Reply