I'm writing an NES emulator in C++ and implemented every instruction for the 6502, accounting for cycles. I can run and pass many different 6502 test programs.
For the last couple weeks, I've been trying to wrap my head around the PPU. I just don't seem to understand it. I think it might be related to the fact that I haven't actually written any NES roms.
I'm thinking if I can write a couple simple ROMS I can maybe wrap my head around it. Is there any easy tutorials out that are recommended for emulator developers?
Is this a good way of possibly fixing my dilemma so I can move on to the PPU?
The PPU is similar to the CPU in the sense that it repeats the same operation over and over, and the values it reads from ROM and RAM generate different results.
While the CPU fetches instructions from memory and executes them, repeating this process forever, the PPU fetches data from the pattern, name and attribute tables, as well as from palette RAM and from OAM, to generate all the pixels in a frame, repeating this process forever.
Additionally, there are some configurable parameters that affect how the picture is rendered, such as what memory is used for what purpose, what the point of origin for the background is (i.e. the scroll), and so on. These are changed by the game program through the registers mapped at $2000-$2007 in the CPU address space. These registers are also used to write and read data to/from PPU memory.
If it's your first emulator, don't insist on getting everything perfect the first time. Make a basic PPU renderer. You'll need to get registers functional so the CPU will manipulate PPU memory so that you have something to actually draw on screen. Once you have that, you can make a basic render for single screen games like Donkey Kong just by drawing all the tiles in the nametable on screen, as well as the sprite list.
You can work at making things more accurate as you go. By keeping it simple at first you can gain motivation and more importantly prevent hitting a wall and losing any motivation and giving up.
MottZilla wrote:
If it's your first emulator, don't insist on getting everything perfect the first time. Make a basic PPU renderer. You'll need to get registers functional so the CPU will manipulate PPU memory so that you have something to actually draw on screen. Once you have that, you can make a basic render for single screen games like Donkey Kong just by drawing all the tiles in the nametable on screen, as well as the sprite list.
You can work at making things more accurate as you go. By keeping it simple at first you can gain motivation and more importantly prevent hitting a wall and losing any motivation and giving up.
So you're saying to wait until vblank and then on the first vblank pixel start walking the PPU memory to dump everything to the screen?
No, just simulate the very very basics of the PPU, namely that there is vblank NMI interrupts that can be turned on and off, and the frame should happen every 341*262 dots (divide by 3 for CPU cycles). Also vblank time ends after 21 scanlines, and the screen starts rendering at that time.
Then just write some function that draws the whole screen. Not simulating any PPU or anything, just draw what the screen would be given what you know at the start of the frame. Even this simple and inaccurate PPU would be good enough for Megaman 2, not quite good enough for Super Mario Bros though.
The relevant parts include: Character data, nametable data, attribute table data, scroll values, and nametable mirroring. Then sprites too.
Then when you're done with that, you can throw that out and write a real PPU.
Dwedit said the basic idea of what I meant. As he said for relatively simple games or ones that don't do anything very tricky you can emulate the PPU very inaccurately and not notice anything is wrong. Games that have a status bar are doing something a bit tricky and require a more accurate PPU simulation. But games that don't like single screen games Donkey Kong, Mario Bros (not Super), Mega Man, Contra, etc. you can emulate much easier.
You only need a very rough approximation of time for many games also. So just keeping track of the CPU's cycles used you can do as Dwedit suggested and check when the cyclecounter is greater than (341*262)/3 which is approx 29780. Whenever the counter exceeds that number you just reset the counter or subtract 29780 from the counter and that is when you do your simulation of vblank as well as drawing your screen. Keep in mind this is just basic and not how you'll do it later on.
So when your counter overflows, you'll need to set the VBlank flag in the $2002 register as well as check the control register to see if you need the CPU to generate a NMI interrupt. In this same period of time you would do as you said, look at PPU memory and start drawing things accordingly. This type of method will allow you to play many games.